]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-19990317
authorWietse Venema <wietse@porcupine.org>
Wed, 17 Mar 1999 05:00:00 +0000 (00:00 -0500)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 02:54:16 +0000 (21:54 -0500)
224 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/INSTALL
postfix/LDAP_README [new file with mode: 0644]
postfix/Makefile.in
postfix/PCRE_README [new file with mode: 0644]
postfix/RELEASE_NOTES
postfix/bounce/.indent.pro
postfix/bounce/Makefile.in
postfix/bounce/bounce.c
postfix/bounce/bounce_notify_service.c [moved from postfix/bounce/bounce_flush_service.c with 53% similarity]
postfix/bounce/bounce_service.h
postfix/cleanup/.indent.pro
postfix/cleanup/cleanup.c
postfix/cleanup/cleanup_envelope.c
postfix/cleanup/cleanup_message.c
postfix/cleanup/cleanup_rewrite.c
postfix/conf/main.cf
postfix/conf/master.cf
postfix/conf/postfix-script-nosgid
postfix/conf/postfix-script-sgid
postfix/conf/sample-local.cf
postfix/conf/sample-misc.cf
postfix/conf/sample-pcre.cf [new file with mode: 0644]
postfix/conf/sample-smtp.cf
postfix/conf/sample-smtpd.cf
postfix/contrib/regexp/pcre [new file with mode: 0644]
postfix/dns/.indent.pro
postfix/dns/dns.h
postfix/dns/dns_rr.c
postfix/dns/snd.h [new file with mode: 0644]
postfix/fsstone/.indent.pro
postfix/global/.indent.pro
postfix/global/Makefile.in
postfix/global/bounce.h
postfix/global/clnt_stream.c [new file with mode: 0644]
postfix/global/clnt_stream.h [new file with mode: 0644]
postfix/global/defer.c
postfix/global/defer.h
postfix/global/deliver_completed.c
postfix/global/deliver_pass.c [new file with mode: 0644]
postfix/global/deliver_request.h
postfix/global/header_opts.c
postfix/global/mail_addr_crunch.c
postfix/global/mail_copy.c
postfix/global/mail_copy.h
postfix/global/mail_date.c
postfix/global/mail_error.c
postfix/global/mail_error.h
postfix/global/mail_flush.c
postfix/global/mail_params.c
postfix/global/mail_params.h
postfix/global/mail_queue.c
postfix/global/mail_queue.h
postfix/global/mail_scan_dir.c [new file with mode: 0644]
postfix/global/mail_scan_dir.h [new file with mode: 0644]
postfix/global/mail_version.c [new file with mode: 0644]
postfix/global/mail_version.h
postfix/global/peer_name.c [moved from postfix/util/peer_name.c with 100% similarity]
postfix/global/peer_name.h [moved from postfix/util/peer_name.h with 100% similarity]
postfix/global/rec_type.c
postfix/global/rec_type.h
postfix/global/resolve_clnt.c
postfix/global/rewrite_clnt.c
postfix/html/Makefile.in
postfix/html/anatomy.html [deleted file]
postfix/html/architecture.html
postfix/html/backstage.html
postfix/html/basic.html
postfix/html/big-picture.html
postfix/html/commands.html
postfix/html/config.html [deleted file]
postfix/html/delivering.html
postfix/html/faq.html
postfix/html/goals.html
postfix/html/index.html
postfix/html/local.8.html
postfix/html/master.8.html
postfix/html/motivation.html
postfix/html/overview.html [deleted file]
postfix/html/pickup.8.html
postfix/html/pipe.8.html
postfix/html/postconf.1.html
postfix/html/postdrop.1.html
postfix/html/postsuper.1.html [new file with mode: 0644]
postfix/html/qmgr.8.html
postfix/html/queuing.html
postfix/html/rate.html
postfix/html/receiving.html
postfix/html/resource.html
postfix/html/rewrite.html
postfix/html/security.html
postfix/html/sendmail.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/html/uce.html
postfix/local/.indent.pro
postfix/local/Makefile.in
postfix/local/alias.c
postfix/local/command.c
postfix/local/dotforward.c
postfix/local/file.c
postfix/local/include.c
postfix/local/local.c
postfix/local/local.h
postfix/local/mailbox.c
postfix/local/maildir.c
postfix/local/recipient.c
postfix/local/resolve.c
postfix/local/unknown.c [new file with mode: 0644]
postfix/makedefs
postfix/man/Makefile.in
postfix/man/man1/postconf.1
postfix/man/man1/postdrop.1
postfix/man/man1/postsuper.1 [new file with mode: 0644]
postfix/man/man1/sendmail.1
postfix/man/man8/local.8
postfix/man/man8/master.8
postfix/man/man8/pickup.8
postfix/man/man8/pipe.8
postfix/man/man8/qmgr.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/master/.indent.pro
postfix/master/Makefile.in
postfix/master/mail_server.h
postfix/master/master.c
postfix/master/master.h
postfix/master/master_ent.c
postfix/master/master_sig.c
postfix/master/master_spawn.c
postfix/master/master_vars.c
postfix/master/master_wakeup.c
postfix/master/multi_server.c
postfix/master/single_server.c
postfix/master/trigger_server.c
postfix/pickup/.indent.pro
postfix/pickup/Makefile.in
postfix/pickup/pickup.c
postfix/pipe/.indent.pro
postfix/pipe/pipe.c
postfix/postalias/.indent.pro
postfix/postcat/.indent.pro
postfix/postcat/postcat.c
postfix/postconf/.indent.pro
postfix/postconf/Makefile.in
postfix/postconf/postconf.c
postfix/postdrop/.indent.pro
postfix/postdrop/postdrop.c
postfix/postfix/.indent.pro
postfix/postkick/.indent.pro
postfix/postlock/.indent.pro
postfix/postlog/.indent.pro
postfix/postmap/.indent.pro
postfix/postsuper/.indent.pro [new file with mode: 0644]
postfix/postsuper/.printfck [new file with mode: 0644]
postfix/postsuper/Makefile.in [new file with mode: 0644]
postfix/postsuper/postsuper.c [new file with mode: 0644]
postfix/qmgr/.indent.pro
postfix/qmgr/Makefile.in
postfix/qmgr/qmgr.c
postfix/qmgr/qmgr.h
postfix/qmgr/qmgr_active.c
postfix/qmgr/qmgr_deliver.c
postfix/qmgr/qmgr_entry.c
postfix/qmgr/qmgr_message.c
postfix/qmgr/qmgr_move.c
postfix/qmgr/qmgr_queue.c
postfix/qmgr/qmgr_scan.c
postfix/qmgr/qmgr_transport.c
postfix/sendmail/.indent.pro
postfix/sendmail/sendmail.c
postfix/showq/.indent.pro
postfix/showq/Makefile.in
postfix/showq/showq.c
postfix/smtp/.indent.pro
postfix/smtp/Makefile.in
postfix/smtp/smtp.c
postfix/smtp/smtp_addr.c
postfix/smtp/smtp_connect.c
postfix/smtp/smtp_proto.c
postfix/smtpd/.indent.pro
postfix/smtpd/Makefile.in
postfix/smtpd/smtpd.c
postfix/smtpd/smtpd_check.c
postfix/smtpd/smtpd_check.in
postfix/smtpd/smtpd_check.in2
postfix/smtpd/smtpd_check.ref
postfix/smtpd/smtpd_check.ref2
postfix/smtpstone/.indent.pro
postfix/smtpstone/hashed-deferred [new file with mode: 0644]
postfix/smtpstone/hashed-incoming [new file with mode: 0644]
postfix/smtpstone/smtp-sink.c
postfix/smtpstone/smtp-source.c
postfix/trivial-rewrite/.indent.pro
postfix/trivial-rewrite/rewrite.c
postfix/trivial-rewrite/transport.c
postfix/util/.indent.pro
postfix/util/Makefile.in
postfix/util/binhash.c
postfix/util/binhash.h
postfix/util/dict_db.c
postfix/util/dict_ldap.c
postfix/util/dict_ldap.h
postfix/util/dict_open.c
postfix/util/dict_pcre.c [new file with mode: 0644]
postfix/util/dict_pcre.h [new file with mode: 0644]
postfix/util/dict_unix.c [new file with mode: 0644]
postfix/util/dict_unix.h [new file with mode: 0644]
postfix/util/events.c
postfix/util/events.h
postfix/util/htable.c
postfix/util/htable.h
postfix/util/scan_dir.c
postfix/util/scan_dir.h
postfix/util/select_bug.c [new file with mode: 0644]
postfix/util/sys_defs.h
postfix/util/valid_hostname.c
postfix/util/valid_hostname.h
postfix/util/valid_hostname.in [new file with mode: 0644]
postfix/util/valid_hostname.ref [new file with mode: 0644]
postfix/util/vstream.c
postfix/util/vstream.h
postfix/util/vstream_popen.c

index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 33722da0f4fd5a17b98474168b0bdd2f220e5d6d..befee96ddcd966e33f5e9e19cbfa76826dae7698 100644 (file)
@@ -817,7 +817,7 @@ Apologies for any names omitted.
        are gone and have become db (dbm, nis, etc) maps. Files:
        smtpd/smtpd_check.c, config/main.cf.
 
-1998029-31
+19980729-31
 
        Feature: hashed queues. Rewrote parts of the mail queue
        API.  Configuration parameters: "hash_queue_names" specifies
@@ -1981,7 +1981,7 @@ Apologies for any names omitted.
 
        Portability: doze() function for systems without usleep().
 
-       Cleanup: clients are logged as host[address].
+       Cleanup: clients are now consistently logged as host[address].
 
 19990122
 
@@ -2063,3 +2063,314 @@ Apologies for any names omitted.
        Requested by Matthew Green and others. Files: local/alias.c,
        global/split_addr.c. This affects canonical, virtual and
        alias lookups.
+
+19990204
+
+       Portability: signal handling for HP-UX 9 by Lamont Jones
+       of Hewlett Packard. File: master/master_sig.c.
+
+       Robustness: disable random walk inside a per-site queue to
+       avoid message starvation under heavy load. File: qmgr_entry.c.
+
+       Robustness: under some conditions the queue manager could
+       declare a host dead after just one delivery failure.  File:
+       qmgr_queue.c.
+
+19990212
+
+       Feature: skip SMTP servers that greet us with a 4XX status
+       code. Example: "smtp_skip_4xx_greeting = yes". By default,
+       the Postfix SMTP client defers delivery when a server
+       declines talking to us. File:  smtp/smtp_connect.c.
+
+       Robustness: upon startup the queue manager now moves active
+       queue files to the incoming queue instead of the deferred
+       queue, to avoid anomalous delivery delays on systems that
+       have a huge incoming queue.  Files: qmgr/qmgr.c,
+       qmgr/qmgr_active.c, global/mail_flush.c, conf/postfix-script*
+
+19990213
+
+       Robustness: added watchdog timers to avoid getting stuck
+       on systems with broken select() socket implementations.
+       File: qmgr_transport.c, qmgr_deliver.c.
+
+19990218
+
+       Feature: NFS-friendly delivery to mailbox by avoiding the
+       use of root privileges as much as possible. With input by
+       Mike Muus, Army Research Lab, USA.
+
+       Feature: the smtp-sink test server now supports SMTP command
+       pipelining. To this end we had to generalize the timer and
+       vstream support. Poor performance is fixed 19990222.
+
+       Cleanup: timer event routines now have the same interface
+       as read/write event routines (event type + context). File:
+       util/events.c.
+
+       Feature: new vstream_peek() routine to tell how much unread
+       data is left in a VSTREAM buffer. This is the vstream
+       variant of the peekfd() routine for kernel read buffers.
+       File: util/vstream.c.
+
+       Feature: directory scanning support for hashed mail queue
+       directories. So far the results are disappointing: with
+       depth = 2 (16 directories with 16 subdirectories), mailq
+       takes 5 seconds with an empty queue unless all directories
+       happen to be cached in memory.  We need a bit map before
+       hashed queue directories become practical. Depth=1 hashing
+       doesn't slow down mailq much, but doesn't help much either.
+       Files: util/scan_dir.c, global/mail_scan_dir.c.
+
+19990221
+
+       Workaround: with "ignore_mx_lookup_error = yes", the SMTP
+       client always performs an A lookup when an MX lookup could
+       not be completed, rather than treating MX lookup failure
+       as a temporary error condition.  Unfortunately there are
+       many broken DNS servers on the Internet. File: smtp/smtp_addr.c.
+
+19990222
+
+       Performance: rewrote the guts of the smtp-sink test server
+       so it can do pipelining without losing performance.
+
+19990223
+
+       Workaround: hotmail.com sometimes drops the connection
+       after "." (causing misleading diagnostics to be logged) or
+       waits minutes after receiving QUIT. Solution: do not wait
+       for the response to QUIT. File: smtp/smtp_proto.c.  This
+       is turned off with: "smtp_skip_quit_response = no".
+
+19990224
+
+       Feature: the pipe mailer accepts user=username:groupname,
+       based on code submitted by Philip A. Prindeville, Mirapoint,
+       Inc., USA.  File: pipe/pipe.c.
+
+       Workaround: use file locking to prevent multiple processes
+       from select()ing on the same socket. This causes performance
+       problems on large BSD systems. Files: master/*_server.c.
+
+19990225
+
+       Bugfix: with "inet_interfaces = 127.0.0.1", don't bind to
+       the loopback interface. Problem reported by Steve Bellovin
+       of AT&T. File: smtp/smtp_addr.c.
+
+       Feature: "postsuper" command to remove stale queue files
+       to update queues after changes to the queue structure
+       parameters (hash_queue_names, hash_queue_depth). This
+       command is to be run from the postfix-script maintenance
+       shell script.
+
+19990301
+
+       Feature: new postconf -h (suppress `name = ' in output)
+       option to make the program easier to use in, e.g., shell
+       scripts.
+
+       Feature: dict_unix module so you can add the UNIX passwd
+       table to the SMTPD access control list.
+
+19990302
+
+       Feature: "luser_relay = destination" captures mail for
+       non-existent local recipients. This works only when the
+       local delivery agent does mailbox delivery (including
+       delivery via mailbox_command), not when mailbox delivery
+       is delegated to another message transport.
+
+       Feature: new reject_non_fqdn_{hostname,sender,recipient}
+       restrictions to require fully.qualified.domain forms in
+       HELO, MAIL FROM and RCPT TO commands (while still allowing
+       the <> sender address).
+
+19990304
+
+       Bugfix: backed out the 19990119 change to always insert
+       Return-Path:  if that header is not present. The pipe and
+       local agents now are responsible for prepending Return-Path:.
+       Files:  cleanup/cleanup_message.c, global/mail_copy.[hc],
+       pipe/pipe.c, global/header_opts.c.  This causes an incompatible
+       change to the pipe flags parameter, because Return-Path:
+       now must be requested explicitly.
+
+19990305
+
+       Bugfix: showq (the mailq server) incorrectly assumed that
+       all recipients of a deferred message are listed in the
+       corresponding defer logfile. It now lists all recipients.
+       Files: showq/showq.c, cleanup/cleanup_envelope.c (ensure
+       that sender records always precede recipient records).
+
+       Cleanup: smtpd HELO restrictions validate [numerical] forms.
+       Files: util/valid_hostname.c, smtpd/smtpd_check.c.  Initial
+       code by Philip A. Prindeville, Mirapoint, Inc., USA.
+
+19990306
+
+       Cleanup: re-vamped the valid_hostname module, and added a
+       maximal label length (63) requirement.
+
+       Feature: fallback_relay parameter to specify extra backup
+       hosts in case the regular relay hosts are not found or not
+       available.  Files:  smtp/smtp_addr.c.
+
+       Feature: "always_bcc = address" specifies where to send a
+       copy of each message that enters he system. However, if
+       that copy bounces, the sender will be informed of the
+       bounce. Files: smtpd/smtpd.c, pickup/pickup.c
+
+       Compatibility: the transport map will now route on top-level
+       domains, so you can dump all of .bitnet to a bitnet relay.
+
+19990307
+
+       Feature: LDAP lookups, updated by Jon Hensley, Merit
+       Network, USA.
+
+       Feature: regular expression (PCRE) support by Andrew
+       McNamara, connect.com.au Pty. Ltd., Australia. In order to
+       use this code specify pcre:/file/name. You can use this
+       anywhere you would use a DB or DBM file, NIS or LDAP.
+       See: PCRE_README for how to enable this code.
+
+       Feature: "delay_warning_time = 4" causes Postfix to send
+       a "your mail is delayed" notice after approx. 4 hours.
+       Daniel Eisenbud, University of California at Berkeley.
+       Files:  qmgr/qmgr_active.c, qmgr/qmgr_message. Postmaster
+       notices for delayed mail are disabled by default. In order
+       to receive postmaster notices, specify "notify_classes =
+       ...  delay ...".
+
+       Cleanup: do not send undeliverable bounced mail to postmaster.
+       This was causing lots of pain with junk mail from bogus
+       sender addresses to non-existent recipients.  This change
+       was reversed 19990311.
+
+19990308
+
+       Bugfix: the dotforward routine was too eager with throwing
+       away extension information, so that the Delivered-To: info
+       would differ for \mailbox and |command. Problem reported
+       by Rafi Sadowski, Open University, Israel.
+
+       Bugfix: seems I never got around to fix the btree access
+       method. I finally did. Problem reported by: Matt Smith,
+       AvTel Communications Inc., USA.
+
+19990311
+
+       Back by popular demand: with "notify_classes = 2bounce ..."
+       Postfix will send undeliverable bounced mail to postmaster.
+       The default is to not send double bounces.  This change
+       reverses a change made on 19990307.
+
+19990312
+
+       Feature: configurable exit handler for server skeletons.
+       Philip A.  Prindeville, Mirapoint, Inc., USA. Files:
+       master/*server.c.
+
+       Feature: mail_spool_directory configuration parameter to
+       specify the UNIX mail spool directory.  The default setting
+       is system dependent.
+
+19990313
+
+       Cleanup: share file descriptors for resolve and rewrite
+       client connections. This puts less strain on the trivial-rewrite
+       service.
+
+       Portability: support for UnixWare 2.1 by Dmitry E. Kiselyov,
+       Nizhny Novgorod City Health Emergency Station.
+
+       Feature: configurable delays in the smtpstone test programs.
+       With input by Philip A.  Prindeville, Mirapoint, Inc., USA.
+       Files:  smtpstone/*.c.
+
+       Bugfix: a "signal 11" problem in the trivial-rewrite program
+       that would occasionally happen after "postfix reload".
+       Reason: some rewrite clients would clobber their input,
+       and when they had to retransmit the query, the input would
+       be a zero-length string, which trivial-rewrite isn't supposed
+       to receive.
+
+19990314
+
+       Feature: "mailbox_transport = cyrus" delegates all local
+       mailbox delivery to a master.cf entry called "cyrus" (the
+       same trick for procmail), including users not found in the
+       UNIX passwd database.  This gives the flexibility of $name
+       expansions by the pipe mailer, without losing local aliases
+       and ~/.forward processing.  Result of discussions with Rupa
+       Schomaker, RS Consulting.
+
+19990315
+
+       Feature: the mydestination parameter can now be an empty
+       string, for hosts that don't receive any mail locally. Be
+       sure to specify a default route for mail that comes to the
+       machine or mail will loop.
+
+19990316
+
+       Bugfix: the SMTPD check scaffolding didn't apply the same
+       sanity checks as the production code. Problem reported by
+       Alain Thivillon, Hervé Schauer Consultants, France. File:
+       smtpd/smtpd_check.c.
+
+       Portability: some systems can have more than 59 seconds in
+       a minute. Based on a fix by Liviu Daia, Institute of
+       Mathematics, Romanian Academy.  File:  global/mail_date.c.
+
+       Enhancement: include the client network address in the
+       rejected by RBL response. Lamont Jones, Hewlett-Packard.
+       
+       Workaround: use fstat() to figure out if the maildrop is
+       world-writable. access() uses the real uid, which stinks.
+
+       Robustness: don't do partial address lookups (user@, domain,
+       user, @domain) with regexp-style tables.
+
+       Security: don't allow regexp-style tables to be used for
+       aliases. It would be too easy to slip in "|command" or
+       :include: or /file/name.
+
+19990317
+
+       Feature: "fallback_transport = cyrus" delegates non-UNIX
+       recipients to a master.cf entry called "cyrus", allowing
+       you to have both UNIX and non-UNIX mailboxes side by side.
+
+Future:
+
+       Planned: must be able to list the same hash table in
+       virtual_maps and mydestination.
+
+       Planned: delivered-to cache instead of table.
+
+       Planned: hide internal loop info so that delivered-to is
+       no longer required.
+
+       Planned: DNS lookups for address canonicalization.
+
+       Planned: no more slow-down when qmgr reaches the end of
+       the in-memory recipient list while there's still more
+       recipients in the queue file.
+
+       Planned: pop pre-authentication by Joerg Henne.
+
+       Planned: ident lookup by Jon Ribbens.
+
+       Planned: $logname, $home, $shell, $user, $sender expansions
+       in shell commands, mailbox_command, forward_path.
+
+       Planned: forward_path, for example $home/.forward (default)
+       or /var/forward/$logname (for mail servers).
+
+       Planned: control From_, Return-Path, Delivered-To and other
+       features with local delivery to mailbox or command.
index 126049c85854df7ebdacdb7e996bb1dc27ea9b3b..9ea47b9c68ba329904c3ae909c99a69c3377aa79 100644 (file)
@@ -54,6 +54,7 @@ If your system is supported, it is one of
     BSD/OS 4.x
     FreeBSD 2.x
     FreeBSD 3.x
+    FreeBSD 4.x
     HP-UX  9.x
     HP-UX 10.x
     HP-UX 11.x
@@ -110,7 +111,7 @@ of the compiler:
     % make makefiles CC="purify cc"
     % make
 
-and so on. On some cases, optimization is turned off automatically.
+and so on. In some cases, optimization is turned off automatically.
 
 In order to build with non-default settings, for example, with a
 configuration directory other than /etc/postfix, use:
@@ -172,7 +173,7 @@ Installing Postfix by hand takes only a few steps.
     # chmod 755 /etc/postfix
     # cp /some/where/postfix/conf/* /etc/postfix
     # chmod 644 /etc/postfix/*
-    # chmod 755 /etc/postfix/postfix-script
+    # chmod 755 /etc/postfix/postfix-script*
 
   This also installs the LICENSE file, as required.
 
diff --git a/postfix/LDAP_README b/postfix/LDAP_README
new file mode 100644 (file)
index 0000000..e07308c
--- /dev/null
@@ -0,0 +1,197 @@
+BUILDING WITH LDAP SUPPORT
+==========================
+
+You need to have LDAP libraries and include files installed somewhere on
+your system, and you need to configure the Postfix Makefiles
+accordingly.
+
+If you're using the libraries from the UM distribution
+(http://www.umich.edu/~dirsvcs/ldap/ldap.html) or OpenLDAP
+(http://www.openldap.org), something like this should work:
+
+    % make tidy
+    % make makefiles CCARGS="-I/some/where/include -DHAS_LDAP" \
+           AUXLIBS="/some/where/libldap.a /some/where/liblber.a"
+
+The `make tidy' command is needed only if you have previously built
+Postfix without LDAP support.
+
+If your LDAP libraries were built with Kerberos support, you'll also
+need to include your Kerberos libraries in this line. Note that the KTH
+Kerberos IV libraries might conflict with Postfix's lib/libdns.a, which
+defines dns_lookup. If that happens, you'll probably want to link with
+LDAP libraries that lack Kerberos support just to build Postfix, as it
+doesn't yet support Kerberos binds to the LDAP server anyway. Sorry
+about the bother.
+
+If you're using one of the Netscape LDAP SDKs, you'll need to change the
+AUXLIBS line to point to libldap10.so or libldapssl30.so or whatever you
+have, and you may need to use the -R option so the executables can find
+it at runtime.
+
+USING LDAP LOOKUPS
+==================
+
+In order to use LDAP lookups, define at least one LDAP source as a table
+lookup in main.cf, for example:
+
+    alias_maps = hash:/etc/aliases, ldap:ldapsource
+
+Each LDAP source can have the following parameters, which should be
+prefixed in main.cf with the name you've given the source in its
+definition. To continue the example, the first parameter below,
+"server_host", would be defined in main.cf as "ldapsource_server_host". 
+Defaults are given in parentheses:
+
+    server_host (localhost)
+       The name of the host running the LDAP server, e.g.
+               ldapsource_server_host = ldap.your.com
+       It should be possible with all the libraries mentioned above to 
+       specify multiple servers separated by spaces, with the libraries
+       trying them in order should the first one fail.
+
+    server_port (389) 
+       The port the LDAP server listens on, e.g.
+               ldapsource_server_port = 778
+
+    search_base (no default)
+       The base at which to conduct the search, e.g. 
+               ldapsource_search_base = dc=your, dc=com
+
+    timeout (10 seconds)
+       The number of seconds a search can take before timing out, e.g.
+               ldapsource_timeout = 5
+       
+    query_filter (mailacceptinggeneralid=%s)
+       The RFC2254 filter used to search the directory, where %s is a 
+       substitute for the address Postfix is trying to resolve, e.g.
+               ldapsource_query_filter = (&(mail=%s)(paid_up=true))
+
+    result_attribute (maildrop)
+       The attribute Postfix will read from any directory entries
+       returned by the lookup, to be resolved to an email address.
+               ldapsource_result = mailbox
+
+    bind (yes)
+       Whether or not to bind to the LDAP server. Newer LDAP
+       implementations don't require clients to bind, which saves
+       time. Example:
+               ldapsource_bind = no
+
+    bind_dn ("")
+       If you do have to bind, do it with this distinguished name.
+       Example:
+               ldapsource_bind_dn = uid=postfix, dc=your, dc=com
+
+    bind_pw ("")
+       The password for the distinguished name above. If you have to
+       have this, you probably want to make main.cf readable only by
+       the Postfix user. Example:
+               ldapsource_bind_pw = postfixpw
+
+Don't use quotes in these variables; at least, not until the Postfix
+configuration routines understand how to deal with quoted strings.
+
+EXAMPLE
+=======
+
+Here's a basic example. In main.cf, you have these configuration
+parameters defined:
+
+alias_maps = hash:/etc/aliases, ldap:ldapsource
+ldapsource_server_host = ldap.my.com
+ldapsource_search_base = dc=my, dc=com
+
+Upon receiving mail for a local address "ldapuser" that isn't found in
+the /etc/aliases database, Postfix will search the LDAP server listening
+at port 389 on ldap.my.com. It will bind anonymously, search for any
+directory entries whose mailacceptinggeneralid attribute is "ldapuser",
+read the "maildrop" attributes of those found, and build a list of their
+maildrops, which will be treated as RFC822 addresses to which the
+message will be delivered.
+
+NOTES AND THINGS TO THINK ABOUT
+===============================
+
+- You probably want to make sure that mailacceptinggeneralids are
+  unique, and that not just anyone can specify theirs as postmaster or
+  root, say.
+
+- An entry can have an arbitrary number of maildrops. Maildrops can also
+  be comma-separated lists of addresses. For example, you could define
+  an entry intended for use as a mailing list that looks like this
+  (Warning! Schema made up just for this example):
+
+  dn: cn=Accounting Staff List, dc=my, dc=com
+  cn: Accounting Staff List
+  o: my.com
+  objectclass: maillist
+  mailacceptinggeneralid: accountingstaff
+  mailacceptinggeneralid: accounting-staff
+  maildrop: mylist-owner
+  maildrop: an-accountant
+  maildrop: some-other-accountant
+  maildrop: this, that, theother
+
+- If you use an LDAP map for lookups other than aliases, you may have to
+  make sure the lookup makes sense. In the case of virtual lookups,
+  maildrops like "|/some/program" are pretty useless. Your query_filter
+  should probably look something like this:
+
+  virtual_query_filter = 
+       (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*"))))
+
+- And for that matter, you may not want users able to specify their
+  maildrops as programs, particularly if they'd be executed on the
+  server. A safer local query_filter could look something like:
+
+  local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*"))(owner=cn=root, dc=your, dc=com)))
+
+  So that if the object had a program as its maildrop and weren't owned
+  by "cn=root" it wouldn't be returned as a valid local user. This will
+  probably require some thought on your part to implement safely,
+  considering the ramifications of includes and programs. You may decide
+  it's not worth the bother to allow any of that nonsense in LDAP
+  lookups, ban it in the query_filter, and keep things like majordomo
+  lists in local alias databases.
+
+- It's not yet known how all this scales, but LDAP lookups are much more
+  expensive than checking a DB file. If you anticipate a lot of lookups,
+  it may pay to plan your directory to reduce the number of lookups. For
+  instance, rather than having a bunch of objects that serve as aliases
+  to just one object, you could simply add their mailacceptinggeneralids
+  to the target object. This:
+
+       dn: uid=firstlast, dc=your, dc=com
+       maildrop: firstlast@mailbox.your.com
+       mailacceptinggeneralid: firstlast
+       mailacceptinggeneralid: First.Last
+       mailacceptinggeneralid: F.Last
+
+  Not this:
+  
+       dn: uid=firstlast, dc=your, dc=com
+       maildrop: firstlast@mailbox.your.com
+       mailacceptinggeneralid: firstlast
+
+       dn: cn=First.Last, dc=your, dc=com
+       maildrop: firstlast
+       mailacceptinggeneralid: First.Last
+
+       dn: cn=F.Last, dc=your, dc=com
+       maildrop: firstlast
+       mailacceptinggeneralid: F.Last
+
+  Any performance reports will be much appreciated on the postfix-users
+  list.
+
+CREDITS
+=======
+
+Support for LDAP was initially written by Prabhat K Singh of VSNL,
+Bombay, India, and then hideously bloated by John Hensley to support
+multiple sources and more configurable attributes. The caching bits were
+initially worked out by Prabhat, then munged to support the multiple
+sources. Other contributions have been submitted to move toward better
+support of Netscape/LDAPv3 libraries, and any other improvements are of
+course welcome.
index e718d0104e27b32a90a448f87023a8aa4ef57591..cccfb2469f1899e1aebe90f7973040b13346c100 100644 (file)
@@ -4,7 +4,7 @@ OPTS    = "CC=$(CC)"
 DIRS   = util global dns master postfix smtpstone fsstone sendmail \
        pickup cleanup smtpd local trivial-rewrite qmgr smtp bounce pipe \
        showq postalias postcat postconf postdrop postkick postlock postlog \
-       postmap # man html
+       postmap postsuper # man html
 
 default: update
 
diff --git a/postfix/PCRE_README b/postfix/PCRE_README
new file mode 100644 (file)
index 0000000..d407d5e
--- /dev/null
@@ -0,0 +1,45 @@
+To: wietse@porcupine.org (Wietse Venema)
+Cc: postfix-users@postfix.org (Postfix users)
+Subject: regexp map patch
+In-reply-to: Your message of "Thu, 25 Feb 1999 19:51:25 CDT."
+             <19990226005125.69B3C4596E@spike.porcupine.org> 
+Date: Tue, 02 Mar 1999 11:04:02 +1100
+From: Andrew McNamara <andrewm@connect.com.au>
+Message-Id: <19990302000403.074C7ED7D@melang.off.connect.com.au>
+Sender: owner-postfix-users@postfix.org
+Precedence: bulk
+Return-Path: <owner-postfix-users@postfix.org>
+
+I've written [code] to add a regexp map type. It utilises the PCRE
+library (Perl Compatible Regular Expressions), which can be obtained
+from:
+
+   ftp://ftp.cus.cam.ac.uk/pub/software/programs/pcre/
+
+You will need to add -DHAS_PCRE and a -I for the PCRE header to CCARGS,
+and add the path to the PCRE library to AUXLIBS, for example:
+
+   make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.04' \
+      'AUXLIBS=../../pcre-2.04/libpcre.a'
+
+One possible use is to add a line to main.cf:
+
+   smtpd_recipient_restrictions = pcre:/opt/postfix/etc/smtprecipient
+
+The regular expressions are read from the file specified and compiled -
+a sample regexp file for this usage is included in the patch.
+
+Any feedback is appreciated (from Wietse in particular :-). Have
+fun.
+
+[I've changed the code so that it can be used for other Postfix
+table lookups, not just for junk mail control. In particular,
+regular expressions in canonical tables could be very useful.
+
+For the sake of robustness, I have disabled the matching of partial
+addresses (user@, domain, user, @domain) that is normally done with
+Postfix access control tables, canonical maps and virtual maps.
+
+As a side effect, pcre maps can only match user@domain strings, so
+that regexps cannot be used for local alias database lookups.  That
+would be a security exposure anyway -- Wietse.]
index 0e9cef7ce52a4da89e44e88dec829abcee176cbd..712ed3c0c639749dd72e83a48b28fb8b9841e90f 100644 (file)
@@ -1,3 +1,88 @@
+Incompatible changes with postfix-alpha-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 since postfix-beta-19990122-pl01:
+===============================================
+
+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.
+
+- Use "$alias_maps, unix:passwd.byname" in smtpd access tables to
+recognize known local users. We're almost there with stopping
+unknown users at the RCPT TO command - the syntax for virtual maps
+and sendmail access tables is too different.
+
+- 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:
 =====================================================
 
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 3279399a67bed1bd3c337a331c8b08611f365974..d9d93153a506238bb45358fe2a4e6428a9d49d48 100644 (file)
@@ -1,7 +1,7 @@
 SHELL  = /bin/sh
-SRCS   = bounce.c bounce_append_service.c bounce_flush_service.c \
+SRCS   = bounce.c bounce_append_service.c bounce_notify_service.c \
        bounce_cleanup.c
-OBJS   = bounce.o bounce_append_service.o bounce_flush_service.o \
+OBJS   = bounce.o bounce_append_service.o bounce_notify_service.o \
        bounce_cleanup.o
 HDRS   = 
 TESTSRC        = 
@@ -91,31 +91,31 @@ bounce_cleanup.o: ../include/vbuf.h
 bounce_cleanup.o: ../include/mail_queue.h
 bounce_cleanup.o: ../include/vstream.h
 bounce_cleanup.o: bounce_service.h
-bounce_flush_service.o: bounce_flush_service.c
-bounce_flush_service.o: ../include/sys_defs.h
-bounce_flush_service.o: ../include/msg.h
-bounce_flush_service.o: ../include/vstring.h
-bounce_flush_service.o: ../include/vbuf.h
-bounce_flush_service.o: ../include/vstream.h
-bounce_flush_service.o: ../include/vstring_vstream.h
-bounce_flush_service.o: ../include/mymalloc.h
-bounce_flush_service.o: ../include/stringops.h
-bounce_flush_service.o: ../include/events.h
-bounce_flush_service.o: ../include/line_wrap.h
-bounce_flush_service.o: ../include/name_mask.h
-bounce_flush_service.o: ../include/mail_queue.h
-bounce_flush_service.o: ../include/mail_proto.h
-bounce_flush_service.o: ../include/iostuff.h
-bounce_flush_service.o: ../include/quote_822_local.h
-bounce_flush_service.o: ../include/mail_params.h
-bounce_flush_service.o: ../include/canon_addr.h
-bounce_flush_service.o: ../include/is_header.h
-bounce_flush_service.o: ../include/record.h
-bounce_flush_service.o: ../include/rec_type.h
-bounce_flush_service.o: ../include/config.h
-bounce_flush_service.o: ../include/post_mail.h
-bounce_flush_service.o: ../include/cleanup_user.h
-bounce_flush_service.o: ../include/mail_addr.h
-bounce_flush_service.o: ../include/mark_corrupt.h
-bounce_flush_service.o: ../include/mail_error.h
-bounce_flush_service.o: bounce_service.h
+bounce_notify_service.o: bounce_notify_service.c
+bounce_notify_service.o: ../include/sys_defs.h
+bounce_notify_service.o: ../include/msg.h
+bounce_notify_service.o: ../include/vstring.h
+bounce_notify_service.o: ../include/vbuf.h
+bounce_notify_service.o: ../include/vstream.h
+bounce_notify_service.o: ../include/vstring_vstream.h
+bounce_notify_service.o: ../include/mymalloc.h
+bounce_notify_service.o: ../include/stringops.h
+bounce_notify_service.o: ../include/events.h
+bounce_notify_service.o: ../include/line_wrap.h
+bounce_notify_service.o: ../include/name_mask.h
+bounce_notify_service.o: ../include/mail_queue.h
+bounce_notify_service.o: ../include/mail_proto.h
+bounce_notify_service.o: ../include/iostuff.h
+bounce_notify_service.o: ../include/quote_822_local.h
+bounce_notify_service.o: ../include/mail_params.h
+bounce_notify_service.o: ../include/canon_addr.h
+bounce_notify_service.o: ../include/is_header.h
+bounce_notify_service.o: ../include/record.h
+bounce_notify_service.o: ../include/rec_type.h
+bounce_notify_service.o: ../include/config.h
+bounce_notify_service.o: ../include/post_mail.h
+bounce_notify_service.o: ../include/cleanup_user.h
+bounce_notify_service.o: ../include/mail_addr.h
+bounce_notify_service.o: ../include/mark_corrupt.h
+bounce_notify_service.o: ../include/mail_error.h
+bounce_notify_service.o: bounce_service.h
index 1698130d78da7ddd8b1c2bf23375fbc16e7d4b1e..f550c2190955a631f764925b3b0317c9d3b12df5 100644 (file)
   * Tunables.
   */
 int     var_bounce_limit;
+int     var_max_queue_time;
+int     var_delay_warn_time;
 char   *var_notify_classes;
 
  /*
@@ -150,9 +152,9 @@ static int bounce_append_proto(char *service_name, VSTREAM *client)
                                  STR(recipient), STR(why)));
 }
 
-/* bounce_flush_proto - bounce_flush server protocol */
+/* bounce_notify_proto - bounce_notify server protocol */
 
-static int bounce_flush_proto(char *service_name, VSTREAM *client)
+static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
 {
     int     flags;
 
@@ -173,7 +175,7 @@ static int bounce_flush_proto(char *service_name, VSTREAM *client)
        return (-1);
     }
     if (msg_verbose)
-       msg_info("bounce_flush_proto: service=%s queue=%s id=%s sender=%s",
+       msg_info("bounce_notify_proto: service=%s queue=%s id=%s sender=%s",
                 service_name, STR(queue_name), STR(queue_id), STR(sender));
 
     /*
@@ -186,8 +188,8 @@ static int bounce_flush_proto(char *service_name, VSTREAM *client)
     /*
      * Execute the request.
      */
-    return (bounce_flush_service(service_name, STR(queue_name),
-                                STR(queue_id), STR(sender)));
+    return (bounce_notify_service(service_name, STR(queue_name),
+                                STR(queue_id), STR(sender), flush));
 }
 
 /* bounce_service - parse bounce command type and delegate */
@@ -210,11 +212,16 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
      * Read and validate the first parameter of the client request. Let the
      * request-specific protocol routines take care of the remainder.
      */
+#define REALLY_BOUNCE  1
+#define JUST_WARN      0
+
     if (mail_scan(client, "%d", &command) != 1) {
        msg_warn("malformed request");
        status = -1;
     } else if (command == BOUNCE_CMD_FLUSH) {
-       status = bounce_flush_proto(service_name, client);
+       status = bounce_notify_proto(service_name, client, REALLY_BOUNCE);
+    } else if (command == BOUNCE_CMD_WARN) {
+       status = bounce_notify_proto(service_name, client, JUST_WARN);
     } else if (command == BOUNCE_CMD_APPEND) {
        status = bounce_append_proto(service_name, client);
     } else {
@@ -263,6 +270,8 @@ int     main(int argc, char **argv)
 {
     static CONFIG_INT_TABLE int_table[] = {
        VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
+       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 0,
+       VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
        0,
     };
     static CONFIG_STR_TABLE str_table[] = {
similarity index 53%
rename from postfix/bounce/bounce_flush_service.c
rename to postfix/bounce/bounce_notify_service.c
index 32f79d7643f795f1ab71b28eca54f1a6c18285b8..ae8889bc8362ed9cb98a678d6b7a4013f2f757fb 100644 (file)
@@ -1,27 +1,30 @@
 /*++
 /* NAME
-/*     bounce_flush_service 3
+/*     bounce_notify_service 3
 /* SUMMARY
 /*     send non-delivery report to sender, server side
 /* SYNOPSIS
 /*     #include "bounce_service.h"
 /*
-/*     int     bounce_flush_service(queue_name, queue_id, sender)
+/*     int     bounce_notify_service(queue_name, queue_id, sender, flush)
 /*     char    *queue_name;
 /*     char    *queue_id;
 /*     char    *sender;
+/*     int     flush;
 /* DESCRIPTION
-/*     This module implements the server side of the bounce_flush()
-/*     (send bounce message) request.
+/*     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.
 /*
 /*     When a message bounces, a full copy is sent to the originator,
-/*     and a copy of the diagnostics with message headers is sent to
-/*     the postmaster.  The result is non-zero when the operation
+/*     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 single bounce is sent, the sender address is the empty
-/*     address.  When a double bounce is sent, the sender is taken
-/*     from the configuration parameter \fIdouble_bounce_sender\fR.
+/*     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"
 
 /* bounce_header - generate bounce message header */
 
-static int bounce_header(VSTREAM *bounce, VSTRING *buf, char *dest)
+static int bounce_header(VSTREAM *bounce, VSTRING *buf, const char *dest, int flush)
 {
 
     /*
      * Print a minimal bounce header. The cleanup service will add other
      * headers and will make all addresses fully qualified.
      */
+#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
+
     post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
                      MAIL_ADDR_MAIL_DAEMON);
-    post_mail_fprintf(bounce, *dest == 0 ?
-                     "Subject: Postmaster Copy: Undelivered Mail" :
-                     "Subject: Undelivered Mail Returned to Sender");
-    quote_822_local(buf, *dest == 0 ? mail_addr_postmaster() : dest);
-    post_mail_fprintf(bounce, "To: %s", STR(buf));
+
+    if (flush) {
+       post_mail_fputs(bounce, STREQ(dest, mail_addr_postmaster()) ?
+                       "Subject: Postmaster Copy: Undelivered Mail" :
+                       "Subject: Undelivered Mail Returned to Sender");
+    } else {
+       post_mail_fputs(bounce, STREQ(dest, mail_addr_postmaster()) ?
+                       "Subject: Postmaster Warning: Delayed Mail" :
+                       "Subject: Delayed Mail (still being retried)");
+    }
+    post_mail_fprintf(bounce, "To: %s", STR(quote_822_local(buf, dest)));
     post_mail_fputs(bounce, "");
     return (vstream_ferror(bounce));
 }
 
 /* bounce_boilerplate - generate boiler-plate text */
 
-static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf)
+static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf, int flush)
 {
 
     /*
@@ -121,19 +132,38 @@ static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf)
     post_mail_fprintf(bounce, "This is the %s program at host %s.",
                      var_mail_name, var_myhostname);
     post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce,
+    if (flush) {
+       post_mail_fputs(bounce,
               "I'm sorry to have to inform you that the message returned");
-    post_mail_fprintf(bounce,
+       post_mail_fputs(bounce,
               "below could not be delivered to one or more destinations.");
+    } else {
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce,
+                       "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+                       "Your message could not be delivered for %d hours.",
+                         var_delay_warn_time);
+       post_mail_fprintf(bounce,
+                         "It will be retried until it is %d days old.",
+                         var_max_queue_time);
+    }
+
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce,
                      "For further assistance, please contact <%s>",
                      STR(canon_addr_external(buf, MAIL_ADDR_POSTMASTER)));
-    post_mail_fputs(bounce, "");
-    post_mail_fprintf(bounce,
+    if (flush) {
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
               "If you do so, please include this problem report. You can");
-    post_mail_fprintf(bounce,
+       post_mail_fprintf(bounce,
                   "delete your own text from the message returned below.");
+    }
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
     return (vstream_ferror(bounce));
@@ -262,92 +292,140 @@ static int bounce_original(char *service, VSTREAM *bounce, VSTRING *buf,
     return (status);
 }
 
-/* bounce_flush_service - send a bounce */
+/* bounce_notify_service - send a bounce */
 
-int     bounce_flush_service(char *service, char *queue_name,
-                                    char *queue_id, char *recipient)
+int     bounce_notify_service(char *service, char *queue_name,
+                                char *queue_id, char *recipient, int flush)
 {
     VSTRING *buf = vstring_alloc(100);
-    const char *double_bounce_addr;
-    int     status = 1;
+    int     bounce_status = 1;
+    int     postmaster_status = 1;
     VSTREAM *bounce;
+    int     notify_mask = name_mask(mail_error_masks, var_notify_classes);
 
-#define NULL_RECIPIENT         MAIL_ADDR_EMPTY /* special address */
 #define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
-#define TO_POSTMASTER(addr)    (*(addr) == 0)
 #define NULL_CLEANUP_FLAGS     0
 #define BOUNCE_HEADERS         1
 #define BOUNCE_ALL             0
 
     /*
-     * The choice of sender address depends on recipient address. For a
-     * single bounce (typically 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 local delivery agent gives
-     * special treatment to the resulting bounce message.
+     * The choice of sender address depends on recipient the 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_addr = mail_addr_double_bounce();
 
     /*
-     * Connect to the cleanup service, and request that the cleanup service
-     * takes no special actions in case of problems.
+     * 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 ((bounce = post_mail_fopen_nowait(TO_POSTMASTER(recipient) ?
-                                        double_bounce_addr : NULL_SENDER,
-                                        recipient, NULL_CLEANUP_FLAGS,
-                                        "BOUNCE")) != 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, buf, recipient) == 0
-           && bounce_boilerplate(bounce, buf) == 0
-           && bounce_diagnostics(service, bounce, buf, queue_id) == 0)
-           bounce_original(service, bounce, buf, queue_name, queue_id, BOUNCE_ALL);
-
-       /*
-        * Finish the bounce, and retrieve the completion status.
-        */
-       status = post_mail_fclose(bounce);
+    if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
+       bounce_status = 0;
     }
 
     /*
-     * If not sending to the postmaster or double-bounce pseudo accounts,
-     * send a postmaster copy as if it is a double bounce, so it will not
-     * bounce in case of error. This time, block while waiting for resources
-     * to become available. We know they were available just a split second
-     * ago.
+     * Single bounce failed. Optionally send a double bounce to postmaster.
      */
-    if (status == 0 && !TO_POSTMASTER(recipient)
-       && strcasecmp(recipient, double_bounce_addr) != 0
-       && (MAIL_ERROR_BOUNCE & name_mask(mail_error_masks, var_notify_classes))) {
+#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)
+
+    else if (*recipient == 0) {
+       if (SKIP_IF_BOUNCE || SKIP_IF_DELAY) {
+           bounce_status = 0;
+       } else {
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                mail_addr_postmaster(),
+                                                NULL_CLEANUP_FLAGS,
+                                                "BOUNCE")) != 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, buf, mail_addr_postmaster(), flush)
+                && bounce_diagnostics(service, bounce, buf, queue_id) == 0)
+                   bounce_original(service, bounce, buf, queue_name, queue_id,
+                                   flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+               bounce_status = post_mail_fclose(bounce);
+           }
+       }
+    }
 
-       /*
-        * Send the text with reason for the bounce, and the headers of the
-        * original message. Don't bother sending the boiler-plate text.
-        */
-       bounce = post_mail_fopen(double_bounce_addr, NULL_RECIPIENT,
-                                NULL_CLEANUP_FLAGS, "BOUNCE");
-       if (bounce_header(bounce, buf, NULL_RECIPIENT) == 0
-           && bounce_diagnostics(service, bounce, buf, queue_id) == 0)
-           bounce_original(service, bounce, buf, queue_name, queue_id, BOUNCE_HEADERS);
+    /*
+     * Non-bounce failed. Send a single bounce.
+     */
+    else {
+       if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+                                            NULL_CLEANUP_FLAGS,
+                                            "BOUNCE")) != 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, buf, recipient, flush) == 0
+               && bounce_boilerplate(bounce, buf, flush) == 0
+               && bounce_diagnostics(service, bounce, buf, queue_id) == 0)
+               bounce_original(service, bounce, buf, queue_name, queue_id,
+                               flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+           bounce_status = post_mail_fclose(bounce);
+       }
 
        /*
-        * Finish the bounce, and update the completion status.
+        * 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.
         */
-       status |= post_mail_fclose(bounce);
+#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
+#define WANT_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+
+       if (bounce_status == 0 && (WANT_IF_BOUNCE || 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.
+            */
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                mail_addr_postmaster(),
+                                                NULL_CLEANUP_FLAGS,
+                                                "BOUNCE")) != 0) {
+               if (!bounce_header(bounce, buf, mail_addr_postmaster(), flush)
+                && bounce_diagnostics(service, bounce, buf, queue_id) == 0)
+                   bounce_original(service, bounce, buf, queue_name, queue_id,
+                                   BOUNCE_HEADERS);
+               postmaster_status = post_mail_fclose(bounce);
+           }
+           if (postmaster_status)
+               msg_warn("postmaster notice failed while bouncing to %s",
+                        recipient);
+       }
     }
 
     /*
      * Examine the completion status. Delete the bounce log file only when
-     * the bounce was posted successfully.
+     * the bounce was posted successfully, and only if we are bouncing for
+     * real, not just warning.
      */
-    if (status == 0 && mail_queue_remove(service, queue_id) && errno != ENOENT)
+    if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id)
+       && errno != ENOENT)
        msg_fatal("remove %s %s: %m", service, queue_id);
 
     /*
@@ -355,5 +433,5 @@ int     bounce_flush_service(char *service, char *queue_name,
      */
     vstring_free(buf);
 
-    return (status);
+    return (bounce_status);
 }
index 8584b981045a78d7efed4833dcb8e3f728814117..5385e550fcfe58fb38ff7c729cf8ae3c78370539 100644 (file)
@@ -19,9 +19,9 @@
 extern int bounce_append_service(char *, char *, char *, char *);
 
  /*
-  * bounce_flush_service.c
+  * bounce_notify_service.c
   */
-extern int bounce_flush_service(char *, char *, char *, char *);
+extern int bounce_notify_service(char *, char *, char *, char *, int);
 
  /*
   * bounce_cleanup.c
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 72c64d665e7a7094767fe679efb6565bb4fc07d5..ef6a62d418c4cb74f9c1da8eff5a3efa293e422e 100644 (file)
@@ -169,6 +169,7 @@ char   *var_masq_domains;           /* masquerade domains */
 char   *var_masq_exceptions;           /* users not masqueraded */
 int     var_dup_filter_limit;          /* recipient dup filter */
 char   *var_empty_addr;                        /* destination of bounced bounces */
+int     var_delay_warn_time;           /* delay that triggers warning */
 
  /*
   * Mappings.
@@ -411,6 +412,7 @@ int     main(int argc, char **argv)
        VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0,
        VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0,
        VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
+       VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
        0,
     };
     static CONFIG_STR_TABLE str_table[] = {
index 5824139f54eecccb78eadd8cb7bb12ebc63f042f..fbef42f97c3b31afc352c8d5aafe681281d588f4 100644 (file)
@@ -57,6 +57,7 @@ void    cleanup_envelope(void)
 {
     VSTRING *clean_addr = vstring_alloc(100);
     int     type = 0;
+    long    warn_time = 0;
 
     /*
      * The message content size record goes first, so it can easily be
@@ -78,6 +79,12 @@ void    cleanup_envelope(void)
            if (cleanup_sender == 0 || cleanup_time == 0) {
                msg_warn("missing sender or time envelope record");
                cleanup_errs |= CLEANUP_STAT_BAD;
+           } else {
+               if (warn_time == 0 && var_delay_warn_time > 0)
+                   warn_time = cleanup_time + var_delay_warn_time * 3600L;
+               if (warn_time)
+                   cleanup_out_format(REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
+                                      warn_time);
            }
            break;
        }
@@ -106,6 +113,11 @@ void    cleanup_envelope(void)
            if (cleanup_sender == 0)
                cleanup_sender = mystrdup(STR(clean_addr));
        } else if (type == REC_TYPE_RCPT) {
+           if (cleanup_sender == 0) {          /* protect showq */
+               msg_warn("envelope recipient precedes sender");
+               cleanup_errs |= CLEANUP_STAT_BAD;
+               break;
+           }
            cleanup_rewrite_internal(clean_addr, *STR(cleanup_inbuf) ?
                                     STR(cleanup_inbuf) : var_empty_addr);
            if (cleanup_rcpt_canon_maps)
@@ -115,6 +127,11 @@ void    cleanup_envelope(void)
            cleanup_out_recipient(STR(clean_addr));
            if (cleanup_recip == 0)
                cleanup_recip = mystrdup(STR(clean_addr));
+       } else if (type == REC_TYPE_WARN) {
+           if ((warn_time = atol(STR(cleanup_inbuf))) < 0) {
+               cleanup_errs |= CLEANUP_STAT_BAD;
+               break;
+           }
        } else {
            CLEANUP_OUT_BUF(type, cleanup_inbuf);
        }
index 32ec19327529a22f835e0561f799a5d4cebaa076..3e5d1dce1de8f00fea68bed4fe9d749d2d8b66d9 100644 (file)
@@ -275,19 +275,6 @@ static void cleanup_missing_headers(void)
     TOK822 *token;
     char   *from;
 
-    /*
-     * Add a missing Return-Path: header when the sender address is not
-     * empty. XXX Shouldn't this depend on the delivery transport being used?
-     * But, it is very tempting to use RFC822 as the basis for our canonical
-     * message representation. And, it is easy to delete an unwanted header.
-     */
-    if (*cleanup_sender != 0
-       && (cleanup_headers_seen & (1 << HDR_RETURN_PATH)) == 0) {
-       quote_822_local(cleanup_temp1, cleanup_sender);
-       cleanup_out_format(REC_TYPE_NORM, "Return-Path: <%s>",
-                          vstring_str(cleanup_temp1));
-    }
-
     /*
      * Add a missing (Resent-)Message-Id: header. The message ID gives the
      * time in GMT units, plus the local queue ID.
@@ -364,7 +351,7 @@ void    cleanup_message(void)
      */
     if ((mesg_offset = vstream_ftell(cleanup_dst)) < 0)
        msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
-    cleanup_out_format(REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0);
+    cleanup_out_format(REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
     if ((data_offset = vstream_ftell(cleanup_dst)) < 0)
        msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
 
index 31cc6ef444483f626a7e29ce5e38a92dee46517c..1ae6871d8bf9f9ef42fa1580d2494384a809acd0 100644 (file)
@@ -77,23 +77,27 @@ void    cleanup_rewrite_external(VSTRING *result, const char *addr)
 
 void    cleanup_rewrite_tree(TOK822 *tree)
 {
-    VSTRING *temp = vstring_alloc(100);
+    VSTRING *dst = vstring_alloc(100);
+    VSTRING *src = vstring_alloc(100);
 
-    tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
-    cleanup_rewrite_external(temp, STR(temp));
+    tok822_externalize(src, tree->head, TOK822_STR_DEFL);
+    cleanup_rewrite_external(dst, STR(src));
     tok822_free_tree(tree->head);
-    tree->head = tok822_scan(STR(temp), &tree->tail);
-    vstring_free(temp);
+    tree->head = tok822_scan(STR(dst), &tree->tail);
+    vstring_free(dst);
+    vstring_free(src);
 }
 
 /* cleanup_rewrite_internal - rewrite address internal form */
 
 void    cleanup_rewrite_internal(VSTRING *result, const char *addr)
 {
-    VSTRING *temp = vstring_alloc(100);
-
-    quote_822_local(temp, addr);
-    cleanup_rewrite_external(temp, STR(temp));
-    unquote_822_local(result, STR(temp));
-    vstring_free(temp);
+    VSTRING *dst = vstring_alloc(100);
+    VSTRING *src = vstring_alloc(100);
+
+    quote_822_local(src, addr);
+    cleanup_rewrite_external(dst, STR(src));
+    unquote_822_local(result, STR(dst));
+    vstring_free(dst);
+    vstring_free(src);
 }
index dcdd3cea3ac1b36f735ae68aa6c1d3e74fd93561..d47113a760f8a2dddd8efbea5c9433b79fe91d69 100644 (file)
@@ -212,16 +212,48 @@ program_directory = /some/where/postfix/bin
 #
 #home_mailbox = Mailbox
 #home_mailbox = Maildir/
-
-# The mailbox_command specifies the optional external command to use
-# instead of mailbox delivery. The command is run with proper HOME,
-# SHELL and LOGNAME settings.
+# The mail_spool_directory parameter specifies the directory where
+# UNIX-style mailboxes are kept. The default setting depends on the
+# system type.
+#
+# mail_spool_directory = /var/mail
+# mail_spool_directory = /var/spool/mail
+
+# The mailbox_command parameter specifies the optional external
+# command to use instead of mailbox delivery. The command is run as
+# the recipient with proper HOME, SHELL and LOGNAME settings.
+# Exception:  delivery for root is done as $default_user.
 # 
 # Avoid shell meta characters because they will force Postfix to run
 # an expensive shell process. Procmail alone is expensive enough.
 #
 #mailbox_command = /some/where/procmail
 
+# The mailbox_transport specifies the optional transport in master.cf
+# to use after processing aliases and .forward files. This parameter
+# has precedence over the mailbox_command, fallback_transport and
+# luser_relay parameters.
+#
+#mailbox_transport = cyrus
+
+# The fallback_transport specifies the optional transport in master.cf
+# to use for recipients that are not found in the UNIX passwd database.
+# This parameter has precedence over the luser_relay parameter.
+#
+#fallback_transport =
+
+# The luser_relay parameter specifies an optional destination 
+# (@domain, address, "|command", /file/name) for unknown recipients.
+# By default, mail for unknown local recipients is bounced.
+#
+# Specify @domain in order to keep the original recipient name.
+# If an address is specified, and if a recipient delimiter is 
+# specified, the original recipient name is appended to the addres
+# localpart.
+#
+# luser_relay =
+  
 # JUNK MAIL CONTROLS
 # 
 # The controls listed here are only a very small subset. See the file
@@ -244,7 +276,7 @@ program_directory = /some/where/postfix/bin
 # list this system as their primary or backup MX host. See the
 # permit_mx_backup restriction in the file sample-smtpd.cf.
 #
-#relay_domains = $mydestination, $virtual_domains
+#relay_domains = $mydestination, $virtual_maps
 
 # The mynetworks parameter specifies the list of networks that are
 # local to this machine.  The list is used by the anti-UCE software
index 595cbca3fbce89542702ba79e286ce7bbcf52749..9b991f612a743a96f76b35d2ee4917d62343cac2 100644 (file)
 # option enables symbolic debugging (see the debugger_command variable
 # in the main.cf configuration file).
 #
+# In order to use the "uucp" message tranport below, set up entries
+# in the transport table.
+#
+# In order to use the "cyrus" message transport below, configure it
+# in main.cf as the mailbox_transport.
+#
 # ==========================================================================
 # service type private unpriv  chroot  wakeup  maxproc command + args
 #              (yes)   (yes)   (yes)   (never) (50)
@@ -55,7 +61,7 @@ defer   unix  -       -       n       -       0       bounce
 smtp     unix  -       -       n       -       -       smtp
 showq     unix n       -       n       -       -       showq
 local    unix  -       n       n       -       -       local
-#local   unix  -       n       n       -       -       pipe
-#    user=cyrus argv=/cyrus/bin/deliver -e -q -m ${extension} ${user}
+cyrus    unix  -       n       n       -       -       pipe
+    flags=R user=cyrus argv=/cyrus/bin/deliver -e -q -m ${extension} ${user}
 uucp     unix  -       n       n       -       -       pipe
     flags=F user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
index a4545bf7d409ec49e1b0cc5ee17cf25586f98038..6a5ac4fc1cc0cf894f6438c2045b5bf123c5812b 100755 (executable)
@@ -141,7 +141,7 @@ reload)
                exit 1
        }
        $INFO refreshing the Postfix mail system
-       kill -HUP `cat pid/master.pid`
+       kill -HUP `sed 1q pid/master.pid`
        ;;
 
 flush)
@@ -150,7 +150,7 @@ flush)
                $FATAL no Postfix queue directory $queue_directory!
                exit 1
        }
-       $command_directory/postkick public qmgr DFA
+       $command_directory/postkick public qmgr IDFA
        ;;
 
 check)
@@ -204,6 +204,8 @@ check)
            ! \( -type p -o -type s \) ! -user $mail_owner \
                -exec $WARN not owned by $mail_owner: {} \;
 
+       $command_directory/postsuper || exit 1
+
        find corrupt -type f -exec $WARN damaged message: {} \;
 
        # XXX also: look for weird stuff, weird permissions, etc.
index 62ba510fdc89ba07d313dc072c5671392b7d2648..cfbc171c9a87f29b594f14bd4d1c23726a48d5d2 100755 (executable)
@@ -141,7 +141,7 @@ reload)
                exit 1
        }
        $INFO refreshing the Postfix mail system
-       kill -HUP `cat pid/master.pid`
+       kill -HUP `sed 1q pid/master.pid`
        ;;
 
 flush)
@@ -150,7 +150,7 @@ flush)
                $FATAL no Postfix queue directory $queue_directory!
                exit 1
        }
-       $command_directory/postkick public qmgr DFA
+       $command_directory/postkick public qmgr IDFA
        ;;
 
 check)
@@ -205,6 +205,8 @@ check)
            ! \( -type p -o -type s \) ! -user $mail_owner \
                -exec $WARN not owned by $mail_owner: {} \;
 
+       $command_directory/postsuper || exit 1
+
        find corrupt -type f -exec $WARN damaged message: {} \;
 
        # XXX also: look for weird stuff, weird permissions, etc.
index 66f978029469bdaa9b711454855de38afa136e09..f0ccfcc423788f46b5d74604b323d20196a73d0a 100644 (file)
@@ -58,9 +58,28 @@ default_privs = nobody
 # home_mailbox = Maildir/
 home_mailbox = 
 
-# The mailbox_command specifies the optional external command to use
-# instead of mailbox delivery. The command is run with proper HOME,
-# SHELL and LOGNAME settings.
+# The luser_relay parameter specifies an optional destination
+# (@domain, address, "|command", /file/name) for unknown recipients.
+# By default, mail for unknown local recipients is bounced.
+#
+# Specify @domain in order to keep the original recipient name.
+# If an address is specified, and if a recipient delimiter is
+# specified, the original recipient name is appended to the addres
+# localpart.
+#
+# luser_relay =
+
+# The mail_spool_directory parameter specifies the directory where
+# UNIX-style mailboxes are kept. The default setting depends on the
+# system type.
+#
+# mail_spool_directory = /var/mail
+# mail_spool_directory = /var/spool/mail
+
+# The mailbox_command parameter specifies the optional external
+# command to use instead of mailbox delivery. The command is run
+# as the recipient with proper HOME, SHELL and LOGNAME settings.
+# Exception: delivery for root is done as $default_user.
 # 
 # Avoid shell meta characters because they will force Postfix to run
 # an expensive shell process. Procmail alone is expensive enough.
@@ -68,6 +87,19 @@ home_mailbox =
 # mailbox_command = /some/where/procmail
 mailbox_command = 
 
+# The mailbox_transport specifies the optional transport in master.cf
+# to use after processing aliases and .forward files. This parameter
+# has precedence over the mailbox_command, fallback_transport and
+# luser_relay parameters.
+#
+mailbox_transport =
+
+# The fallback_transport specifies the optional transport in master.cf
+# to use for recipients that are not found in the UNIX passwd database.
+# This parameter has precedence over the luser_relay parameter.
+#
+fallback_transport =
+
 #
 # RATE CONTROLS
 #
index c211f0133992001c80301c0c1cacf9a0f49f8b3a..d8b25fdc8abe2a190a04d8002028199e9494a0b7 100644 (file)
@@ -1,6 +1,12 @@
 # This file contains example settings for miscellaneous Postfix
 # configuration parameters.
 
+# The always_bcc parameter specifies an optional address that
+# receives a copy of each message that enters the Postfix system,
+# not including bounces that are generated locally.
+#
+always_bcc =
+
 # The default_database_type parameter specifies the default database
 # type to use in postalias(1) and postmap(1) commands. On many UNIX
 # systems the default type is either `dbm' or `hash'. The default is
@@ -27,16 +33,26 @@ double_bounce_sender = double-bounce
 # levels below the queue directories listed in the hash_queue_names
 # parameter.
 # 
-# Multiple subdirectory levels can speed up directory searches by
+# Multiple subdirectory levels can speed up directory access by
 # reducing the number of files per directory.
 #
+# After changing the hash_queue_names or hash_queue_depth parameter,
+# run "postfix reload" and "postfix check".
+#
 hash_queue_depth = 2
 
 # The hash_queue_names parameter specifies the names of queue
 # directories that are split across multiple subdirectory levels.
-# Currently, hashing cannot be used for the maildrop, incoming, active
-# or deferred directories. Hashing MUST be used for the defer logfile
-# directory, or mail system performance will suffer.
+# Hashing MUST NOT be used with a world-writable maildrop directory.
+# Hashing MUST be used for the defer logfile directory, or mail system
+# performance will suffer.
+#
+# Unfortunately, hashing the incoming or deferred queue can actually
+# slow the mail system down (mailq with an empty queue can take
+# several seconds) so it should be done only in case of emergency.
+#
+# After changing the hash_queue_names or hash_queue_depth parameter,
+# run "postfix reload" and "postfix check".
 #
 hash_queue_names = defer
 
@@ -165,7 +181,8 @@ myorigin = $myhostname
 # policy (anti-UCE violations) and protocol error (broken mailers)
 # reports.
 #
-# notify_classes = bounce,policy,protocol,resource,software
+# notify_classes = bounce,delay,policy,protocol,resource,software
+# notify_classes = 2bounce,resource,software
 notify_classes = resource,software
 
 # The process_id_directory specifies a lock file directory relative
@@ -230,3 +247,9 @@ relocated_maps =
 # mail system is under heavy load.
 #
 trigger_timeout = 10
+
+# The delay_warning_time specifies after how many hours a warning
+# is sent that mail has not yet been delivered. By default, no warning
+# is sent.
+#
+# delay_warning_time = 0
diff --git a/postfix/conf/sample-pcre.cf b/postfix/conf/sample-pcre.cf
new file mode 100644 (file)
index 0000000..2bfa1a1
--- /dev/null
@@ -0,0 +1,52 @@
+# 
+#      Sample pcre (PERL-compatible regular expression) map file
+#
+#      The first field is a perl-like regular expression. The expression
+#      delimiter can be any character except whitespace, or characters
+#      that have special meaning to the regexp library (traditionally
+#      the forward slash is used). The regular expression can contain
+#      whitespace.
+#
+#      By default, matching is case-INsensative, although following
+#      the second slash with an 'i' will reverse this. Other flags are
+#      supported, but the only other useful one is 'U', which makes
+#      matching ungreedy (see PCRE documentation and source for more
+#      info).
+#
+#      The second field is the "replacement" string - the text
+#      returned by the match. When used for smtpd checks, this would
+#      be a helpful message to misguided users (or an offensive
+#      message to spammers), although it could also be a domain name
+#      or other data for use as a transport, virtual, or other map.
+#
+#      Substitution of sub-strings from the matched expression is
+#      possible using the conventional perl syntax. The macros in the
+#      replacement string may need to be protected with curly braces
+#      if they aren't followed by whitespace (see the examples
+#      below).
+#
+#      Lines starting with whitespace are continuation lines - they are
+#      appended to the previous line (there should be no whitespace
+#      before your regular expression!)
+#
+#      This code was originally developed for SPAM control. However
+#      it seems that it can be used equally well for address rewriting
+#      by virtual or canonical lookups. Using this for aliases might 
+#      be stretching things, though.
+#
+
+# Protect your outgoing majordomo exploders
+#
+/^(?!owner-)(.*)-outgoing@(connect.com.au)$/   550 Use ${1}@${2} instead
+
+
+# Bounce friend@whatever, except when whatever is our domain (you would
+# be better just bouncing all friend@ mail - this is just an example).
+#
+/^friend@(?!connect.com.au).*$/                550 Stick this in your pipe $0
+
+# A multi-line response
+#
+/^noddy@connect.com.au$/
+ 550 This user is a funny one. You really don't want to send mail to them
+ as it only makes their head spin. 
index e1868b4b44ef17fbb8389d592ff4015633d5f7af..64ac7d7516d7480955c0adfc9d636e18c2b64087 100644 (file)
@@ -1,6 +1,39 @@
 # This file contains example settings of Postfix configuration
 # parameters that control the SMTP client program.
 
+#
+# MISCELLANEOUS CONTROLS
+#
+
+# The fallback_relay parameter specifies zero or more hosts or domains
+# to hand off mail to if a message destination is not found, or if a
+# destination is unreachable.
+#
+# By default, mail is bounced when a destination is not found, and
+# delivery is deferred if a destination is unreachable.
+#
+fallback_relay = 
+
+# The ignore_mx_lookup_error parameter controls what happens when a
+# name server fails to respond to an MX lookup request. By default,
+# Postfix defers delivery and tries again after some delay. Specify
+# "ignore_mx_lookup_error = yes" to force an A record lookup instead.
+#
+ignore_mx_lookup_error = no
+
+# The smtp_skip_4xx_greeting parameter controls what happens when
+# an SMTP server greets us with a 4XX status code. By default, Postfix
+# backs off. Specify "smtp_skip_4xx_greeting = yes" to move on the
+# the next mail exchanger.
+# 
+smtp_skip_4xx_greeting = no
+
+# The smtp_skip_quit_response parameter controls whether the SMTP
+# client waits for the response to the QUIT command. The default is
+# to not wait.
+# 
+smtp_skip_quit_response = yes
+
 #
 # RATE CONTROLS
 #
index 51c4e87f3e98d8d0d38b42ad9c3baade139e966e..6bea9dc2425039fe7b9f2588c3eb1660fe1efa70 100644 (file)
@@ -99,6 +99,7 @@ smtpd_helo_required = no
 #   permit_mynetworks: permit if the client address matches $mynetworks.
 #   reject_invalid_hostname: reject HELO hostname with bad syntax.
 #   reject_unknown_hostname: reject HELO hostname without DNS A record.
+#   reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form
 #   maptype:mapname: look up HELO hostname or parent domains.
 #                   Reject if result is REJECT or "[45]xx text"
 #                   Permit otherwise.
@@ -130,6 +131,8 @@ smtpd_helo_restrictions =
 #                   Permit otherwise.
 #   check_client_access maptype:mapname: see smtpd_client_restrictions.
 #   check_helo_access maptype:mapname: see smtpd_helo_restrictions.
+#   reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form
+#   reject_non_fqdn_sender: reject sender address that is not in FQDN form
 #   reject: reject the request. Place this at the end of a restriction.
 #   permit: permit the request. Place this at the end of a restriction.
 #
@@ -162,6 +165,9 @@ smtpd_sender_restrictions =
 #   check_client_access maptype:mapname: see smtpd_client_restrictions.
 #   check_helo_access maptype:mapname: see smtpd_helo_restrictions.
 #   check_sender_access maptype:mapname: see smtpd_sender_restrictions.
+#   reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form
+#   reject_non_fqdn_sender: reject sender address that is not in FQDN form
+#   reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
 #   reject: reject the request. Place this at the end of a restriction.
 #   permit: permit the request. Place this at the end of a restriction.
 #
@@ -206,7 +212,7 @@ maps_rbl_domains = rbl.maps.vix.com
 # permit_mx_backup restriction, in the description of the
 # smtpd_recipient_restrictions parameter.
 #
-relay_domains = $mydestination, $virtual_domains
+relay_domains = $mydestination, $virtual_maps
 
 #
 # RESPONSE CODES
diff --git a/postfix/contrib/regexp/pcre b/postfix/contrib/regexp/pcre
new file mode 100644 (file)
index 0000000..21bcdbb
--- /dev/null
@@ -0,0 +1,565 @@
+From owner-postfix-users@postfix.org Mon Mar  1 19:04:41 1999
+Delivered-To: wietse@porcupine.org
+Received: from russian-caravan.cloud9.net (russian-caravan.cloud9.net [168.100.1.4])
+       by spike.porcupine.org (Postfix) with ESMTP id 5785A45A72
+       for <wietse@porcupine.org>; Mon,  1 Mar 1999 19:04:36 -0500 (EST)
+Received: by russian-caravan.cloud9.net (Postfix)
+       id 5F5D37638F; Mon,  1 Mar 1999 19:04:08 -0500 (EST)
+Delivered-To: postfix-users-outgoing@cloud9.net
+Received: by russian-caravan.cloud9.net (Postfix, from userid 54)
+       id 322AF76398; Mon,  1 Mar 1999 19:04:08 -0500 (EST)
+Delivered-To: postfix-users@cloud9.net
+Received: from melang.off.connect.com.au (melang.off.connect.com.au [202.21.9.1])
+       by russian-caravan.cloud9.net (Postfix) with ESMTP id 6E87C7638F
+       for <postfix-users@postfix.org>; Mon,  1 Mar 1999 19:04:04 -0500 (EST)
+Received: from connect.com.au (localhost [127.0.0.1])
+       by melang.off.connect.com.au (Postfix) with ESMTP
+       id 074C7ED7D; Tue,  2 Mar 1999 11:04:02 +1100 (EST)
+To: wietse@porcupine.org (Wietse Venema)
+Cc: postfix-users@postfix.org (Postfix users)
+Subject: regexp map patch
+In-reply-to: Your message of "Thu, 25 Feb 1999 19:51:25 CDT."
+             <19990226005125.69B3C4596E@spike.porcupine.org> 
+Date: Tue, 02 Mar 1999 11:04:02 +1100
+From: Andrew McNamara <andrewm@connect.com.au>
+Message-Id: <19990302000403.074C7ED7D@melang.off.connect.com.au>
+Sender: owner-postfix-users@postfix.org
+Precedence: bulk
+Return-Path: <owner-postfix-users@postfix.org>
+Status: RO
+
+I've written a patch to add a regexp map type. It utilises the PCRE
+library (Perl Compatible Regular Expressions), which can be obtained
+from:
+
+   ftp://ftp.cus.cam.ac.uk/pub/software/programs/pcre/
+
+You will need to add -DHAS_PCRE and a -I for the PCRE header to CCARGS,
+and add the path to the PCRE library to AUXLIBS, for example:
+
+   make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.04' \
+      'AUXLIBS=../../pcre-2.04/libpcre.a'
+
+One possible use is to add a line to main.cf:
+
+   smtpd_recipient_restrictions = regexp:/opt/postfix/etc/smtprecipient
+
+The regular expressions are read from the file specified and compiled -
+a sample regexp file for this usage is included in the patch.
+
+Any feedback is appreciated (from Wietse in particular :-). Have fun.
+
+diff -u --recursive orig/postfix-beta-19990122-pl01/conf/sample-regexp postfix-beta-19990122-pl01/conf/sample-regexp
+--- orig/postfix-beta-19990122-pl01/conf/sample-regexp Tue Mar  2 10:42:43 1999
++++ postfix-beta-19990122-pl01/conf/sample-regexp      Tue Mar  2 10:51:49 1999
+@@ -0,0 +1,51 @@
++# 
++#     Sample regexp map source file
++#
++#     The first field is a perl-like regular express. The expression
++#     delimiter can be any character except whitespace, or characters
++#     that have special meaning to the regexp library (traditionally
++#     the forward slash is used). The expression can contain
++#     whitespace.
++#
++#     By default, matching is case-INsensative, although following
++#     the second slash with an 'i' will reverse this. Other flags are
++#     supported, but the only other useful one is 'U', which makes
++#     matching ungreedy (see PCRE documentation and source for more
++#     info).
++#
++#     The second field is the "replacement" string - the text
++#     returned by the match. When used for smtpd checks, this would
++#     be a helpful message to misguided users (or an offensive
++#     message to spammers), although it could also be a domain name
++#     or other data for use as a transport, virtual, or other map.
++#
++#     Substitution of sub-strings from the matched expression is
++#     possible using the conventional perl syntax. The macros in the
++#     replacement string may need to be protected with curly braces
++#     if they aren't followed by whitespace (see the examples
++#     below).
++#
++#     If no second field is given, the text "REJECT" is returned -
++#     this string is magic to the check functions in smtpd, and
++#     results in an "administratively denied relay" message.
++#
++#     Lines starting with whitespace are continuation lines - they are
++#     appended to the previous line (there should be no whitespace
++#     before your regular expression!)
++
++
++# Protect your outgoing majordomo exploders
++#
++/^(.*)-outgoing@(connect.com.au)$/    550 Use ${1}@${2} instead
++
++
++# Bounce friend@whatever, except when whatever is our domain (you would
++# be better just bouncing all friend@ mail - this is just an example).
++#
++/^friend@(?!connect.com.au).*$/               550 Stick this in your pipe $0
++
++# A multi-line response
++#
++/^noddy@connect.com.au$/
++ 550 This user is a funny one. You really don't want to send mail to them
++ as it only makes their head spin. 
+diff -u --recursive orig/postfix-beta-19990122-pl01/util/Makefile.in postfix-beta-19990122-pl01/util/Makefile.in
+--- orig/postfix-beta-19990122-pl01/util/Makefile.in   Sun Jan 31 15:16:15 1999
++++ postfix-beta-19990122-pl01/util/Makefile.in        Fri Feb 26 15:57:24 1999
+@@ -18,7 +18,7 @@
+       timed_wait.c translit.c trimblanks.c unix_connect.c unix_listen.c \
+       unix_trigger.c unsafe.c username.c valid_hostname.c vbuf.c \
+       vbuf_print.c vstream.c vstream_popen.c vstring.c vstring_vstream.c \
+-      writable.c write_buf.c write_wait.c doze.c
++      writable.c write_buf.c write_wait.c doze.c dict_pcre.c
+ OBJS  = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
+       close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
+       dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \
+@@ -38,7 +38,7 @@
+       timed_wait.o translit.o trimblanks.o unix_connect.o unix_listen.o \
+       unix_trigger.o unsafe.o username.o valid_hostname.o vbuf.o \
+       vbuf_print.o vstream.o vstream_popen.o vstring.o vstring_vstream.o \
+-      writable.o write_buf.o write_wait.o doze.o
++      writable.o write_buf.o write_wait.o doze.o dict_pcre.o
+ HDRS  = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
+       dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \
+       dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \
+@@ -51,7 +51,7 @@
+       ring.h safe.h safe_open.h sane_accept.h scan_dir.h set_eugid.h \
+       set_ugid.h sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \
+       timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
+-      vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h
++      vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h dict_pcre.h
+ TESTSRC       = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c
+ WARN  = -W -Wformat -Wimplicit -Wmissing-prototypes \
+       -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
+diff -u --recursive orig/postfix-beta-19990122-pl01/util/dict_open.c postfix-beta-19990122-pl01/util/dict_open.c
+--- orig/postfix-beta-19990122-pl01/util/dict_open.c   Sat Dec 12 05:55:34 1998
++++ postfix-beta-19990122-pl01/util/dict_open.c        Fri Feb 26 15:07:51 1999
+@@ -100,6 +100,7 @@
+ #include <dict_nisplus.h>
+ #include <dict_ni.h>
+ #include <dict_ldap.h>
++#include <dict_pcre.h>
+ #include <stringops.h>
+ #include <split_at.h>
+@@ -131,6 +132,9 @@
+ #endif
+ #ifdef HAS_LDAP
+     "ldap", dict_ldap_open,
++#endif
++#ifdef HAS_PCRE
++    "regexp", dict_pcre_open,
+ #endif
+     0,
+ };
+diff -u --recursive orig/postfix-beta-19990122-pl01/util/dict_pcre.c postfix-beta-19990122-pl01/util/dict_pcre.c
+--- orig/postfix-beta-19990122-pl01/util/dict_pcre.c   Tue Mar  2 10:42:30 1999
++++ postfix-beta-19990122-pl01/util/dict_pcre.c        Tue Mar  2 10:39:37 1999
+@@ -0,0 +1,349 @@
++/*++
++/* NAME
++/*    dict_pcre 3
++/* SUMMARY
++/*    dictionary manager interface to PCRE regular expression library
++/* SYNOPSIS
++/*    #include <dict_pcre.h>
++/*
++/*    DICT    *dict_pcre_open(name, flags)
++/*    const char *name;
++/*    int     flags;
++/* DESCRIPTION
++/*    dict_pcre_open() opens the named file and compiles the contained
++/*    regular expressions.
++/* SEE ALSO
++/*    dict(3) generic dictionary manager
++/* 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
++/*
++/*    Andrew McNamara
++/*    andrewm@connect.com.au
++/*    connect.com.au Pty. Ltd.
++/*    Level 3, 213 Miller St
++/*    North Sydney, NSW, Australia
++/*--*/
++
++#include "sys_defs.h"
++
++#ifdef HAS_PCRE
++
++/* System library. */
++
++#include <stdio.h>                    /* sprintf() prototype */
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++
++/* Utility library. */
++
++#include "mymalloc.h"
++#include "msg.h"
++#include "safe.h"
++#include "vstream.h"
++#include "vstring.h"
++#include "stringops.h"
++#include "readline.h"
++#include "dict.h"
++#include "dict_pcre.h"
++#include "mac_parse.h"
++
++/* PCRE library */
++
++#include "pcre.h"
++
++#define PCRE_MAX_CAPTURE      99      /* Max strings captured by regexp - */
++                                      /* essentially the max number of (..) */
++
++struct dict_pcre_list {
++    pcre        *pattern;             /* The compiled pattern */
++    pcre_extra  *hints;                       /* Hints to speed pattern execution */
++    char      *replace;               /* Replacement string */
++    int               lineno;                 /* Source file line number */
++    struct dict_pcre_list  *next;     /* Next regexp in dict */
++};
++
++typedef struct {
++    DICT        dict;                 /* generic members */
++    char       *map;                  /* map name */
++    int         flags;                        /* unused at the moment */
++    struct dict_pcre_list  *head;
++} DICT_PCRE;
++
++static dict_pcre_init = 0;            /* flag need to init pcre library */
++
++/* 
++ *  dict_pcre_update - not supported
++ */
++static void dict_pcre_update(DICT *dict, const char *unused_name, 
++                      const char *unused_value)
++{
++    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
++
++    msg_fatal("dict_pcre_update: attempt to update regexp map %s", 
++      dict_pcre->map);
++}
++
++/*
++ * Context for macro expansion callback.
++ */
++struct dict_pcre_context {
++    const char        *dict_name;                     /* source dict name */
++    int               lineno;                         /* source file line number */
++    VSTRING   *buf;                           /* target string buffer */
++    const char        *subject;                       /* str against which we match */
++    int               offsets[ PCRE_MAX_CAPTURE * 3 ];/* Cut substrings */
++    int         matches;                      /* Count of cuts */
++};
++
++/*
++ * Macro expansion callback - replace $0-${99} with strings cut from
++ * matched string.
++ */
++static void dict_pcre_action( int type, VSTRING *buf, char *ptr )
++{
++    struct dict_pcre_context *ctxt = (struct dict_pcre_context *) ptr;
++    const char        *pp;
++    int               n, ret;
++
++    if( type == MAC_PARSE_VARNAME ) {
++      n = atoi( vstring_str( buf ));
++      ret = pcre_get_substring( ctxt->subject, ctxt->offsets, ctxt->matches,
++              n, &pp );
++      if( ret < 0 ) {
++          if( ret == PCRE_ERROR_NOSUBSTRING )
++              msg_warn( "regexp %s, line %d: replace index out of range",
++                  ctxt->dict_name, ctxt->lineno );
++          else
++              msg_warn( "regexp %s, line %d: pcre_get_substring error: %d",
++                  ctxt->dict_name, ctxt->lineno, ret );
++          return;
++      }
++      vstring_strcat( ctxt->buf, pp );
++    } else
++      /* Straight text - duplicate with no substitution */
++      vstring_strcat( ctxt->buf, vstring_str(buf));
++}
++
++/*
++ * Look up regexp dict and perform string substitution on matched
++ * strings.
++ */
++static const char *dict_pcre_lookup(DICT *dict, const char *name)
++{
++    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
++    struct dict_pcre_list *pcre_list;
++    int               name_len = strlen( name );
++    struct dict_pcre_context  ctxt;
++    static VSTRING            *buf;
++
++/*    msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name );*/
++
++    /* Search for a matching expression */
++    for( pcre_list = dict_pcre->head; pcre_list; pcre_list = pcre_list->next ) {
++      if( pcre_list->pattern ) {
++          ctxt.matches = pcre_exec( pcre_list->pattern, pcre_list->hints, 
++                  name, name_len, 0, ctxt.offsets, PCRE_MAX_CAPTURE * 3 );
++          if( ctxt.matches != PCRE_ERROR_NOMATCH ) {
++              if( ctxt.matches > 0 )
++                  break;                      /* Got a match! */
++              else {
++                  /* An error */
++                  switch( ctxt.matches ) {
++                  case 0:
++                      msg_warn( "regexp map %s, line %d: too many (...)",
++                              dict_pcre->map, pcre_list->lineno );
++                      break;
++                  case PCRE_ERROR_NULL:
++                  case PCRE_ERROR_BADOPTION:
++                      msg_fatal( "regexp map %s, line %d: bad args to re_exec",
++                              dict_pcre->map, pcre_list->lineno );
++                      break;
++                  case PCRE_ERROR_BADMAGIC:
++                  case PCRE_ERROR_UNKNOWN_NODE:
++                      msg_fatal( "regexp map %s, line %d: corrupt compiled regexp",
++                              dict_pcre->map, pcre_list->lineno );
++                      break;
++                  default:
++                      msg_fatal( "regexp map %s, line %d: unknown re_exec error: %d",
++                              dict_pcre->map, pcre_list->lineno, ctxt.matches );
++                      break;
++                  }
++                  return( (char *)0 );
++              }
++          }
++      }
++    }
++
++    /* If we've got a match, */
++    if ( ctxt.matches > 0 ) {
++      /* And we've got a replacement string, */
++      if ( pcre_list->replace ) {
++          /* Then perform substitution on replacement string */
++          if( buf == 0 )
++              buf = vstring_alloc(10);
++          VSTRING_RESET(buf);
++          ctxt.buf = buf;
++          ctxt.subject = name;
++          ctxt.dict_name = dict_pcre->map;
++          ctxt.lineno = pcre_list->lineno;
++
++          mac_parse( pcre_list->replace, dict_pcre_action, (char *)&ctxt );
++
++          VSTRING_TERMINATE(buf);
++          return( vstring_str( buf ));
++      } else
++          /* No replacement string, so just return dummy */
++          return( "REJECT" );
++    }
++
++    return ( (char *)0 );
++}
++
++/* dict_pcre_close - close pcre dictionary */
++
++static void dict_pcre_close(DICT *dict)
++{
++    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
++    struct dict_pcre_list *pcre_list;
++
++    for( pcre_list = dict_pcre->head; pcre_list; pcre_list = pcre_list->next ) {
++      if( pcre_list->pattern )
++          myfree((char *) pcre_list->pattern);
++      if( pcre_list->hints )
++          myfree((char *) pcre_list->hints);
++      if( pcre_list->replace )
++          myfree((char *) pcre_list->replace);
++    }
++    myfree((char *) dict_pcre);
++}
++
++/*
++ * dict_pcre_open - load and compile a file containing regular expressions
++ */
++DICT   *dict_pcre_open(const char *map, int unused_flags)
++{
++    DICT_PCRE   *dict_pcre;
++    VSTREAM   *map_fp;
++    VSTRING   *line_buffer;
++    struct dict_pcre_list *pcre_list = NULL, *pl;
++    int               lineno = 0;
++    char      *regexp, *p, re_delimiter;
++    int               re_options;
++    pcre      *pattern;
++    pcre_extra        *hints;
++    const char        *error;
++    int               errptr;
++
++    line_buffer = vstring_alloc(100);
++
++    dict_pcre = (DICT_PCRE *) mymalloc(sizeof(*dict_pcre));
++    dict_pcre->dict.lookup = dict_pcre_lookup;
++    dict_pcre->dict.update = dict_pcre_update;
++    dict_pcre->dict.close = dict_pcre_close;
++    dict_pcre->dict.fd = -1;
++    dict_pcre->map = mystrdup(map);
++    dict_pcre->flags = 0;
++    dict_pcre->head = NULL;
++
++    if (dict_pcre_init == 0) {
++      pcre_malloc = (void *)mymalloc;
++      pcre_free = (void *)myfree;
++      dict_pcre_init = 1;
++    }
++
++    if(( map_fp = vstream_fopen( map, O_RDONLY, 0 )) == 0 ) {
++      msg_fatal("open %s: %m", map );
++    }
++    while (readline(line_buffer, map_fp, &lineno)) {
++
++      if (*vstring_str(line_buffer) == '#')           /* Skip comments */
++          continue;
++
++      p = vstring_str(line_buffer);
++      re_delimiter = *p++;
++      regexp = p;
++
++      /* Search for second delimiter, handling backslash escape */
++      while( *p ) {
++          if( *p == re_delimiter && 
++                  ( p > vstring_str(line_buffer) && *(p - 1) != '\\' ))
++              break;
++          ++p;
++      }
++
++      if (!*p) {
++          msg_warn("%s, line %d: no closing regexp delimiter: %c",
++              VSTREAM_PATH(map_fp), lineno, re_delimiter );
++          continue;
++      }
++      *p++ = '\0';                            /* Null term the regexp */
++
++      /* Now parse any regexp options */
++      re_options = PCRE_CASELESS;
++      while( *p && !ISSPACE( *p )) {
++          switch( *p ) {
++              case 'i':       re_options ^= PCRE_CASELESS; break;
++              case 'm':       re_options ^= PCRE_MULTILINE; break;
++              case 's':       re_options ^= PCRE_DOTALL; break;
++              case 'x':       re_options ^= PCRE_EXTENDED; break;
++              case 'A':       re_options ^= PCRE_ANCHORED; break;
++              case 'E':       re_options ^= PCRE_DOLLAR_ENDONLY; break;
++              case 'U':       re_options ^= PCRE_UNGREEDY; break;
++              case 'X':       re_options ^= PCRE_EXTRA; break;
++              default:
++                  msg_warn("%s, line %d: unknown regexp option '%c'",
++                      VSTREAM_PATH(map_fp), lineno, *p );
++          }
++          ++p;
++      }
++
++      while( *p && ISSPACE( *p ))
++          ++p;
++      
++      /* Compile the patern */
++      pattern = pcre_compile( regexp, re_options, &error, &errptr, NULL );
++      if( pattern == NULL ) {
++          msg_warn("%s, line %d: error in regex at offset %d: %s",
++              VSTREAM_PATH(map_fp), lineno, errptr, error );
++          continue;
++      }
++      hints = pcre_study( pattern, 0, &error );
++      if( error != NULL ) {
++          msg_warn("%s, line %d: error while studying regex: %s",
++              VSTREAM_PATH(map_fp), lineno, error );
++          myfree( (char *)pattern );
++          continue;
++      }
++
++      /* Add it to the list */
++      pl = (struct dict_pcre_list *)mymalloc( sizeof( struct dict_pcre_list ));
++
++      /* Save the replacement string (if any) */
++      pl->replace = ( *p ? mystrdup( p ) : NULL );
++      pl->pattern = pattern;
++      pl->hints = hints;
++      pl->next = NULL;
++      pl->lineno = lineno;
++
++      if( pcre_list == NULL )
++          dict_pcre->head = pl;
++      else
++          pcre_list->next = pl;
++      pcre_list = pl;
++    }
++
++    vstring_free(line_buffer);
++    vstream_fclose(map_fp);
++
++    return (&dict_pcre->dict);
++}
++#endif /*HAS_PCRE*/
+diff -u --recursive orig/postfix-beta-19990122-pl01/util/dict_pcre.h postfix-beta-19990122-pl01/util/dict_pcre.h
+--- orig/postfix-beta-19990122-pl01/util/dict_pcre.h   Tue Mar  2 10:42:32 1999
++++ postfix-beta-19990122-pl01/util/dict_pcre.h        Mon Mar  1 18:17:23 1999
+@@ -0,0 +1,41 @@
++#ifndef _DICT_PCRE_H_INCLUDED_
++#define _DICT_PCRE_H_INCLUDED_
++
++/*++
++/* NAME
++/*    dict_pcre 3h
++/* SUMMARY
++/*    dictionary manager interface to PCRE regular expression library
++/* SYNOPSIS
++/*    #include <dict_pcre.h>
++/* DESCRIPTION
++/* .nf
++
++ /*
++  * Utility library.
++  */
++#include <dict.h>
++
++ /*
++  * External interface.
++  */
++extern DICT *dict_pcre_open(const char *, int);
++
++/* 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
++/*
++/*    Andrew McNamara
++/*    andrewm@connect.com.au
++/*    connect.com.au Pty. Ltd.
++/*    Level 3, 213 Miller St
++/*    North Sydney, NSW, Australia
++/*--*/
++
++#endif
+
+ ---
+Andrew McNamara (Senior System Administrator)
+
+connect.com.au Pty Ltd
+Lvl 3, 213 Miller St, North Sydney, NSW 2060, Australia
+Phone: +61 2 9959 5959, Fax: +61 2 9966 1960
+
+
+
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index f2cf0336631e62840c295f7a4dd38faeef2566d5..0d3496c84e737035397a079d832082a5d5a010f4 100644 (file)
@@ -58,7 +58,7 @@
   */
 typedef struct DNS_FIXED {
     unsigned short type;               /* T_A, T_CNAME, etc. */
-    unsigned short class;              /* T_A, T_CNAME, etc. */
+    unsigned short class;              /* C_IN, etc. */
     unsigned int ttl;                  /* always */
     unsigned length;                   /* record length */
 } DNS_FIXED;
@@ -70,7 +70,7 @@ typedef struct DNS_FIXED {
 typedef struct DNS_RR {
     char   *name;                      /* name, mystrdup()ed */
     unsigned short type;               /* T_A, T_CNAME, etc. */
-    unsigned short class;              /* T_A, T_CNAME, etc. */
+    unsigned short class;              /* C_IN, etc. */
     unsigned int ttl;                  /* always */
     unsigned short pref;               /* T_MX only */
     struct DNS_RR *next;               /* linkage */
@@ -95,6 +95,7 @@ extern unsigned dns_type(const char *);
 extern DNS_RR *dns_rr_create(const char *, DNS_FIXED *, unsigned,
                                     const char *, unsigned);
 extern void dns_rr_free(DNS_RR *);
+extern DNS_RR *dns_rr_copy(DNS_RR *);
 extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *));
 
index e6bb5f7a58ead7147170df6b98b42c93a67e8126..39cbf192061ae4c253cf7bbad521f7b0cd7c5ad0 100644 (file)
@@ -16,6 +16,9 @@
 /*     void    dns_rr_free(list)
 /*     DNS_RR  *list;
 /*
+/*     DNS_RR  *dns_rr_copy(record)
+/*     DNS_RR  *record;
+/*
 /*     DNS_RR  *dns_rr_append(list, record)
 /*     DNS_RR  *list;
 /*     DNS_RR  *record;
@@ -38,6 +41,8 @@
 /*     dns_rr_free() releases the resource used by of zero or more
 /*     resource records.
 /*
+/*     dns_rr_copy() makes a copy of a resource record.
+/*
 /*     dns_rr_append() appends a resource record to a (list of) resource
 /*     record(s).
 /*
@@ -102,6 +107,23 @@ void    dns_rr_free(DNS_RR *rr)
     }
 }
 
+/* dns_rr_copy - copy resource record */
+
+DNS_RR *dns_rr_copy(DNS_RR *src)
+{
+    int     len = sizeof(*src) + src->data_len - 1;
+    DNS_RR *dst;
+
+    /*
+     * Combine struct assignment and data copy in one block copy operation.
+     */
+    dst = (DNS_RR *) mymalloc(len);
+    memcpy((char *) dst, (char *) src, len);
+    dst->name = mystrdup(src->name);
+    dst->next = 0;
+    return (dst);
+}
+
 /* dns_rr_append - append resource record to list */
 
 DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
diff --git a/postfix/dns/snd.h b/postfix/dns/snd.h
new file mode 100644 (file)
index 0000000..e69de29
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 9a077980dd0dd395e02131a46d32560d94cfe572..2eb474973ea06ee34ec600bea814cfe6b957bb9e 100644 (file)
@@ -8,14 +8,15 @@ SRCS  = been_here.c bounce.c canon_addr.c clean_env.c cleanup_strerror.c \
        mail_command_write.c mail_connect.c mail_copy.c mail_date.c \
        mail_error.c mail_flush.c mail_open_ok.c mail_params.c \
        mail_pathname.c mail_print.c mail_queue.c mail_run.c mail_scan.c \
-       mail_task.c mail_trigger.c maps.c mark_corrupt.c mkmap_db.c \
-       mkmap_dbm.c mkmap_open.c mynetworks.c mypwd.c namadr_list.c \
-       off_cvt.c opened.c own_inet_addr.c pipe_command.c post_mail.c \
-       quote_822_local.c rec_streamlf.c rec_type.c recipient_list.c \
-       record.c remove.c resolve_clnt.c resolve_local.c rewrite_clnt.c \
-       sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
-       timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
-       tok822_resolve.c tok822_rewrite.c tok822_tree.c mail_stream.c
+       mail_scan_dir.c mail_stream.c mail_task.c mail_trigger.c maps.c \
+       mark_corrupt.c mkmap_db.c mkmap_dbm.c mkmap_open.c mynetworks.c \
+       mypwd.c namadr_list.c off_cvt.c opened.c own_inet_addr.c \
+       peer_name.c pipe_command.c post_mail.c quote_822_local.c \
+       rec_streamlf.c rec_type.c recipient_list.c record.c remove.c \
+       resolve_clnt.c resolve_local.c rewrite_clnt.c sent.c smtp_stream.c \
+       split_addr.c string_list.c sys_exits.c timed_ipc.c tok822_find.c \
+       tok822_node.c tok822_parse.c tok822_resolve.c tok822_rewrite.c \
+       tok822_tree.c clnt_stream.c deliver_pass.c
 OBJS   = been_here.o bounce.o canon_addr.o clean_env.o cleanup_strerror.o \
        config.o config_bool.o config_int.o config_str.o debug_peer.o \
        debug_process.o defer.o deliver_completed.o deliver_flock.o \
@@ -25,27 +26,29 @@ OBJS        = been_here.o bounce.o canon_addr.o clean_env.o cleanup_strerror.o \
        mail_command_write.o mail_connect.o mail_copy.o mail_date.o \
        mail_error.o mail_flush.o mail_open_ok.o mail_params.o \
        mail_pathname.o mail_print.o mail_queue.o mail_run.o mail_scan.o \
-       mail_task.o mail_trigger.o maps.o mark_corrupt.o mkmap_db.o \
-       mkmap_dbm.o mkmap_open.o mynetworks.o mypwd.o namadr_list.o \
-       off_cvt.o opened.o own_inet_addr.o pipe_command.o post_mail.o \
-       quote_822_local.o rec_streamlf.o rec_type.o recipient_list.o \
-       record.o remove.o resolve_clnt.o resolve_local.o rewrite_clnt.o \
-       sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
-       timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
-       tok822_resolve.o tok822_rewrite.o tok822_tree.o mail_stream.o
+       mail_scan_dir.o mail_stream.o mail_task.o mail_trigger.o maps.o \
+       mark_corrupt.o mkmap_db.o mkmap_dbm.o mkmap_open.o mynetworks.o \
+       mypwd.o namadr_list.o off_cvt.o opened.o own_inet_addr.o \
+       peer_name.o pipe_command.o post_mail.o quote_822_local.o \
+       rec_streamlf.o rec_type.o recipient_list.o record.o remove.o \
+       resolve_clnt.o resolve_local.o rewrite_clnt.o sent.o smtp_stream.o \
+       split_addr.o string_list.o sys_exits.o timed_ipc.o tok822_find.o \
+       tok822_node.o tok822_parse.o tok822_resolve.o tok822_rewrite.o \
+       tok822_tree.o clnt_stream.o deliver_pass.o
 HDRS   = been_here.h bounce.h canon_addr.h clean_env.h cleanup_user.h \
        config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
        deliver_flock.h deliver_request.h domain_list.h dot_lockfile.h \
        file_id.h header_opts.h is_header.h mail_addr.h mail_addr_crunch.h \
        mail_addr_find.h mail_addr_map.h mail_copy.h mail_date.h \
        mail_error.h mail_flush.h mail_open_ok.h mail_params.h \
-       mail_proto.h mail_queue.h mail_run.h mail_task.h mail_version.h \
-       maps.h mark_corrupt.h mkmap.h mynetworks.h mypwd.h namadr_list.h \
-       off_cvt.h opened.h own_inet_addr.h pipe_command.h post_mail.h \
+       mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h mail_stream.h \
+       mail_task.h mail_version.h maps.h mark_corrupt.h mkmap.h \
+       mynetworks.h mypwd.h namadr_list.h off_cvt.h opened.h \
+       own_inet_addr.h peer_name.h pipe_command.h post_mail.h \
        quote_822_local.h rec_streamlf.h rec_type.h recipient_list.h \
        record.h resolve_clnt.h resolve_local.h rewrite_clnt.h sent.h \
        smtp_stream.h split_addr.h string_list.h sys_exits.h timed_ipc.h \
-       tok822.h mail_stream.h
+       tok822.h clnt_stream.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -244,6 +247,17 @@ cleanup_strerror.o: ../include/sys_defs.h
 cleanup_strerror.o: ../include/vstring.h
 cleanup_strerror.o: ../include/vbuf.h
 cleanup_strerror.o: cleanup_user.h
+clnt_stream.o: clnt_stream.c
+clnt_stream.o: ../include/sys_defs.h
+clnt_stream.o: ../include/msg.h
+clnt_stream.o: ../include/mymalloc.h
+clnt_stream.o: ../include/vstream.h
+clnt_stream.o: ../include/vbuf.h
+clnt_stream.o: ../include/events.h
+clnt_stream.o: ../include/iostuff.h
+clnt_stream.o: mail_proto.h
+clnt_stream.o: mail_params.h
+clnt_stream.o: clnt_stream.h
 config.o: config.c
 config.o: ../include/sys_defs.h
 config.o: ../include/msg.h
@@ -316,6 +330,16 @@ deliver_flock.o: ../include/vbuf.h
 deliver_flock.o: ../include/myflock.h
 deliver_flock.o: mail_params.h
 deliver_flock.o: deliver_flock.h
+deliver_pass.o: deliver_pass.c
+deliver_pass.o: ../include/sys_defs.h
+deliver_pass.o: ../include/msg.h
+deliver_pass.o: ../include/vstring.h
+deliver_pass.o: ../include/vbuf.h
+deliver_pass.o: ../include/vstream.h
+deliver_pass.o: mail_proto.h
+deliver_pass.o: ../include/iostuff.h
+deliver_pass.o: deliver_request.h
+deliver_pass.o: recipient_list.h
 deliver_request.o: deliver_request.c
 deliver_request.o: ../include/sys_defs.h
 deliver_request.o: ../include/msg.h
@@ -519,6 +543,10 @@ mail_scan.o: ../include/vstring_vstream.h
 mail_scan.o: ../include/mymalloc.h
 mail_scan.o: mail_proto.h
 mail_scan.o: ../include/iostuff.h
+mail_scan_dir.o: mail_scan_dir.c
+mail_scan_dir.o: ../include/sys_defs.h
+mail_scan_dir.o: ../include/scan_dir.h
+mail_scan_dir.o: mail_scan_dir.h
 mail_stream.o: mail_stream.c
 mail_stream.o: ../include/sys_defs.h
 mail_stream.o: ../include/msg.h
@@ -641,6 +669,11 @@ own_inet_addr.o: ../include/inet_addr_host.h
 own_inet_addr.o: ../include/stringops.h
 own_inet_addr.o: mail_params.h
 own_inet_addr.o: own_inet_addr.h
+peer_name.o: peer_name.c
+peer_name.o: ../include/sys_defs.h
+peer_name.o: ../include/msg.h
+peer_name.o: ../include/valid_hostname.h
+peer_name.o: peer_name.h
 pipe_command.o: pipe_command.c
 pipe_command.o: ../include/sys_defs.h
 pipe_command.o: ../include/msg.h
@@ -731,6 +764,7 @@ resolve_clnt.o: ../include/events.h
 resolve_clnt.o: ../include/iostuff.h
 resolve_clnt.o: mail_proto.h
 resolve_clnt.o: mail_params.h
+resolve_clnt.o: clnt_stream.h
 resolve_clnt.o: resolve_clnt.h
 resolve_local.o: resolve_local.c
 resolve_local.o: ../include/sys_defs.h
@@ -752,6 +786,7 @@ rewrite_clnt.o: ../include/iostuff.h
 rewrite_clnt.o: quote_822_local.h
 rewrite_clnt.o: mail_proto.h
 rewrite_clnt.o: mail_params.h
+rewrite_clnt.o: clnt_stream.h
 rewrite_clnt.o: rewrite_clnt.h
 sent.o: sent.c
 sent.o: ../include/sys_defs.h
index 6d1afb1ce589fd938efdd3da5f9b7ddb78a6c8cb..d7cf2f1d98a72c79a5e69cd52eb0fbf2a03eccca 100644 (file)
@@ -31,6 +31,7 @@ extern int bounce_flush(int, const char *, const char *, const char *);
   */
 #define BOUNCE_CMD_APPEND      0       /* append log */
 #define BOUNCE_CMD_FLUSH       1       /* send log */
+#define BOUNCE_CMD_WARN                2       /* send warning bounce, don't delete log */
 
  /*
   * Flags.
diff --git a/postfix/global/clnt_stream.c b/postfix/global/clnt_stream.c
new file mode 100644 (file)
index 0000000..4513247
--- /dev/null
@@ -0,0 +1,207 @@
+/*++
+/* NAME
+/*     clnt_stream 3
+/* SUMMARY
+/*     client endpoint maintenance
+/* SYNOPSIS
+/*     #include <clnt_stream.h>
+/*
+/*     CLNT_STREAM *clnt_stream_create(class, service, timeout)
+/*     const char *class;
+/*     const char *service;
+/*     int     timeout;
+/*
+/*     VSTREAM *clnt_stream_access(clnt_stream)
+/*     CLNT_STREAM *clnt_stream;
+/*
+/*     void    clnt_stream_recover(clnt_stream)
+/*     CLNT_STREAM *clnt_stream;
+/*
+/*     void    clnt_stream_free(clnt_stream)
+/*     CLNT_STREAM *clnt_stream;
+/* DESCRIPTION
+/*     This module maintains local IPC client endpoints that automatically
+/*     disconnect after a being idle for a configurable amount of time,
+/*     and that transparently handle most server-initiated disconnects.
+/*     Server disconnect is detected by read-selecting the client endpoint.
+/*     The code assumes that the server has disconnected when the endpoint
+/*     becomes readable.
+/*
+/*     clnt_stream_create() instantiates a client endpoint.
+/*
+/*     clnt_stream_access() returns an open stream to the service specified
+/*     to clnt_stream_create(). The stream instance may change between calls.
+/*
+/*     clnt_stream_recover() recovers from a server-initiated disconnect
+/*     that happened in the middle of an I/O operation.
+/*
+/*     clnt_stream_free() destroys of the specified client endpoint.
+/* DIAGNOSTICS
+/*     Warnings: communication failure. Fatal error: mail system is down,
+/*     out of memory.
+/* SEE ALSO
+/*     mail_proto(3h) low-level mail component glue.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <events.h>
+#include <iostuff.h>
+
+/* Global library. */
+
+#include "mail_proto.h"
+#include "mail_params.h"
+#include "clnt_stream.h"
+
+/* Application-specific. */
+
+ /*
+  * CLNT_STREAM is an opaque structure. None of the access methods can easily
+  * be implemented as a macro, and access is not performance critica anyway.
+  */
+struct CLNT_STREAM {
+    VSTREAM *vstream;                  /* buffered I/O */
+    int     timeout;                   /* time before client disconnect */
+    char   *class;                     /* server class */
+    char   *service;                   /* server name */
+};
+
+static void clnt_stream_close(CLNT_STREAM *);
+
+/* clnt_stream_event - server-initiated disconnect or client-side timeout */
+
+static void clnt_stream_event(int unused_event, char *context)
+{
+    CLNT_STREAM *clnt_stream = (CLNT_STREAM *) context;
+
+    /*
+     * Sanity check. This routine causes the stream to be closed, so it
+     * cannot be called when the stream is already closed.
+     */
+    if (clnt_stream->vstream == 0)
+       msg_panic("clnt_stream_event: stream is closed");
+
+    clnt_stream_close(clnt_stream);
+}
+
+/* clnt_stream_open - connect to service */
+
+static void clnt_stream_open(CLNT_STREAM *clnt_stream)
+{
+
+    /*
+     * Sanity check.
+     */
+    if (clnt_stream->vstream)
+       msg_panic("clnt_stream_open: stream is open");
+
+    /*
+     * Schedule a read event so that we can clean up when the remote side
+     * disconnects, and schedule a timer event so that we can cleanup an idle
+     * connection. Note that both events are handled by the same routine.
+     */
+    clnt_stream->vstream = mail_connect_wait(clnt_stream->class,
+                                         clnt_stream->service);
+    close_on_exec(vstream_fileno(clnt_stream->vstream), CLOSE_ON_EXEC);
+    event_enable_read(vstream_fileno(clnt_stream->vstream), clnt_stream_event,
+                     (char *) clnt_stream);
+    event_request_timer(clnt_stream_event, (char *) clnt_stream,
+                       clnt_stream->timeout);
+}
+
+/* clnt_stream_close - disconnect from service */
+
+static void clnt_stream_close(CLNT_STREAM *clnt_stream)
+{
+
+    /*
+     * Sanity check.
+     */
+    if (clnt_stream->vstream == 0)
+       msg_panic("clnt_stream_close: stream is closed");
+
+    /*
+     * Be sure to disable read and timer events.
+     */
+    if (msg_verbose)
+       msg_info("%s stream disconnect", clnt_stream->service);
+    event_disable_readwrite(vstream_fileno(clnt_stream->vstream));
+    event_cancel_timer(clnt_stream_event, (char *) clnt_stream);
+    (void) vstream_fclose(clnt_stream->vstream);
+    clnt_stream->vstream = 0;
+}
+
+/* clnt_stream_recover - recover from server-initiated disconnect */
+
+void    clnt_stream_recover(CLNT_STREAM *clnt_stream)
+{
+
+    /*
+     * Clean up. Don't re-connect until the caller needs it.
+     */
+    if (clnt_stream->vstream)
+       clnt_stream_close(clnt_stream);
+}
+
+/* clnt_stream_access - access a client stream */
+
+VSTREAM *clnt_stream_access(CLNT_STREAM *clnt_stream)
+{
+
+    /*
+     * Open a stream or restart the idle timer.
+     */
+    if (clnt_stream->vstream == 0) {
+       clnt_stream_open(clnt_stream);
+    } else {
+       event_request_timer(clnt_stream_event, (char *) clnt_stream,
+                           clnt_stream->timeout);
+    }
+    return (clnt_stream->vstream);
+}
+
+/* clnt_stream_create - create client stream connection */
+
+CLNT_STREAM *clnt_stream_create(const char *class, const char *service,
+                                       int timeout)
+{
+    CLNT_STREAM *clnt_stream;
+
+    /*
+     * Don't open the stream until the caller needs it.
+     */
+    clnt_stream = (CLNT_STREAM *) mymalloc(sizeof(*clnt_stream));
+    clnt_stream->vstream = 0;
+    clnt_stream->timeout = timeout;
+    clnt_stream->class = mystrdup(class);
+    clnt_stream->service = mystrdup(service);
+    return (clnt_stream);
+}
+
+/* clnt_stream_free - destroy client stream instance */
+
+void    clnt_stream_free(CLNT_STREAM *clnt_stream)
+{
+    if (clnt_stream->vstream)
+       clnt_stream_close(clnt_stream);
+    myfree(clnt_stream->class);
+    myfree(clnt_stream->service);
+    myfree((char *) clnt_stream);
+}
diff --git a/postfix/global/clnt_stream.h b/postfix/global/clnt_stream.h
new file mode 100644 (file)
index 0000000..a3d480a
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _CLNT_STREAM_H_INCLUDED_
+#define _CLNT_STREAM_H_INCLUDED_
+
+/*++
+/* NAME
+/*     clnt_stream 3h
+/* SUMMARY
+/*     client socket maintenance
+/* SYNOPSIS
+/*     #include <clnt_stream.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+
+ /*
+  * External interface.
+  */
+typedef struct CLNT_STREAM CLNT_STREAM;
+
+extern CLNT_STREAM *clnt_stream_create(const char *, const char *, int);
+extern VSTREAM *clnt_stream_access(CLNT_STREAM *);
+extern void clnt_stream_recover(CLNT_STREAM *);
+extern void clnt_stream_free(CLNT_STREAM *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index ebb0b3ae985a426904d6bd51a702deed2c97a835..f59e41ccbe6ee18af6f89b8e062538ce9142451f 100644 (file)
 /*     const char *queue;
 /*     const char *id;
 /*     const char *sender;
+/*
+/*     int     defer_warn(flags, queue, id, sender)
+/*     int     flags;
+/*     const char *queue;
+/*     const char *id;
+/*     const char *sender;
 /* DESCRIPTION
 /*     This module implements a client interface to the defer service,
 /*     which maintains a per-message logfile with status records for
@@ -43,6 +49,9 @@
 /*     sender, including the defer log that was built with defer_append().
 /*     The result is zero in case of success, non-zero otherwise.
 /*
+/*     defer_warn() sends a warning message that the mail in question has
+/*     been deferred.  It does not flush the log.
+/*
 /*     Arguments:
 /* .IP flags
 /*     The bit-wise OR of zero or more of the following (specify
@@ -154,3 +163,18 @@ int     defer_flush(int flags, const char *queue, const char *id,
        return (-1);
     }
 }
+
+/* defer_warn - send a copy of the defer log to the sender as a warning bounce
+ * do not flush the log */
+
+int     defer_warn(int flags, const char *queue, const char *id,
+                          const char *sender)
+{
+    if (mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER,
+                          "%d %d %s %s %s", BOUNCE_CMD_WARN,
+                          flags, queue, id, sender) == 0) {
+       return (0);
+    } else {
+       return (-1);
+    }
+}
index 7458f459a128eb091ef9a924845635d3e303839f..ae6385cfce33362a2d3899f5d538373640a5678f 100644 (file)
@@ -31,6 +31,8 @@ extern int vdefer_append(int, const char *, const char *, const char *,
                                 time_t, const char *, va_list);
 extern int defer_flush(int, const char *, const char *, const char *);
 
+extern int defer_warn(int, const char *, const char *, const char *);
+
 /* LICENSE
 /* .ad
 /* .fi
index 485c794f984b190f69ff95f49587a5a7533d6dda..d2bb1ef2dd3dc9fa438ff9fae4733ddc2e84aa25 100644 (file)
@@ -11,7 +11,9 @@
 /*     long    offset;
 /* DESCRIPTION
 /*     deliver_completed() crosses off the specified recipient from
-/*     an open queue file.
+/*     an open queue file. A -1 offset means ignore the request -
+/*     this is used for delivery requests that are passed on from
+/*     one delivery agent to another.
 /* DIAGNOSTICS
 /*     Fatal error: unable to update the queue file.
 /* LICENSE
@@ -46,6 +48,9 @@ void    deliver_completed(VSTREAM *stream, long offset)
 {
     char   *myname = "deliver_completed";
 
+    if (offset == -1)
+       return;
+
     if (offset <= 0)
        msg_panic("%s: bad offset %ld", myname, offset);
 
diff --git a/postfix/global/deliver_pass.c b/postfix/global/deliver_pass.c
new file mode 100644 (file)
index 0000000..31196be
--- /dev/null
@@ -0,0 +1,148 @@
+/*++
+/* NAME
+/*     deliver_pass 3
+/* SUMMARY
+/*     deliver request pass_through
+/* SYNOPSIS
+/*     #include <deliver_request.h>
+/*
+/*     int     deliver_pass(class, service, request, address, offset)
+/*     const char *class;
+/*     const char *service;
+/*     DELIVER_REQUEST *request;
+/*     const char *address;
+/*     long    offset;
+/* DESCRIPTION
+/*     This module implements the client side of the `queue manager
+/*     to delivery agent' protocol, passing one recipient on from
+/*     one delivery agent to another.
+/*
+/*     Arguments:
+/* .IP class
+/*     Destination delivery agent service class
+/* .IP service
+/*     Destination delivery agent service name.
+/* .IP request
+/*     Delivery request with queue file information.
+/* .IP address
+/*     Recipient envelope address.
+/* .IP offset
+/*     Recipient offset in queue file.
+/* DIAGNOSTICS
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* BUGS
+/*     One recipient at a time; this is OK for mailbox deliveries.
+/*
+/*     Hop status information cannot be passed back.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstream.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <deliver_request.h>
+
+/* deliver_pass_initial_reply - retrieve initial delivery process response */
+
+static int deliver_pass_initial_reply(VSTREAM *stream)
+{
+    int     stat;
+
+    if (mail_scan(stream, "%d", &stat) != 1) {
+       msg_warn("%s: malformed response", VSTREAM_PATH(stream));
+       stat = -1;
+    }
+    return (stat);
+}
+
+/* deliver_pass_send_request - send delivery request to delivery process */
+
+static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
+                                            const char *addr, long offs)
+{
+    int     stat;
+
+    mail_print(stream, "%s %s %ld %ld %s %s %s %s %ld %ld %s %s",
+              request->queue_name, request->queue_id,
+              request->data_offset, request->data_size,
+              addr, request->sender,
+              request->errors_to, request->return_receipt,
+              request->arrival_time,
+              offs, addr, "0");
+
+    if (vstream_fflush(stream)) {
+       msg_warn("%s: bad write: %m", VSTREAM_PATH(stream));
+       stat = -1;
+    } else {
+       stat = 0;
+    }
+    return (stat);
+}
+
+/* deliver_pass_final_reply - retrieve final delivery status response */
+
+static int deliver_pass_final_reply(VSTREAM *stream, VSTRING *reason)
+{
+    int     stat;
+
+    if (mail_scan(stream, "%s %d", reason, &stat) != 2) {
+       msg_warn("%s: malformed response", VSTREAM_PATH(stream));
+       stat = -1;
+    }
+    return (stat);
+}
+
+/* deliver_pass - deliver one per-site queue entry */
+
+int     deliver_pass(const char *class, const char *service,
+                     DELIVER_REQUEST *request, const char *addr, long offs)
+{
+    VSTREAM *stream;
+    VSTRING *reason;
+    int     status;
+
+    /*
+     * Initialize.
+     */
+    stream = mail_connect_wait(class, service);
+    reason = vstring_alloc(1);
+
+    /*
+     * Get the delivery process initial response. Send the queue file info
+     * and recipient info to the delivery process. Retrieve the delivery
+     * agent status report. The numerical status code indicates if delivery
+     * should be tried again. The reason text is sent only when a destination
+     * should be avoided for a while, so that the queue manager can log why
+     * it does not even try to schedule delivery to the affected recipients.
+     * XXX Can't pass back hop status info because the problem is with a
+     * different transport.
+     */
+    if ((status = deliver_pass_initial_reply(stream)) == 0
+       && (status = deliver_pass_send_request(stream, request, addr, offs)) == 0)
+       status = deliver_pass_final_reply(stream, reason);
+
+    /*
+     * Clean up.
+     */
+    vstream_fclose(stream);
+    vstring_free(reason);
+
+    return (status);
+}
index d0e3ce6c19bccc77adf6a721d0c54158b3716379..695110fdc5dd45a1b73ac8f43d2e6b73aa7c6bcc 100644 (file)
@@ -43,6 +43,8 @@ typedef struct VSTREAM _deliver_vstream_;
 extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *);
 extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int);
 
+extern int deliver_pass(const char *, const char *, DELIVER_REQUEST *, const char *, long);
+
 /* LICENSE
 /* .ad
 /* .fi
index 91b102a804f89dd518e881219f898bf12d7f0889..e14e31f3cad94e55980e45b95cabf506873ffaa5 100644 (file)
@@ -66,7 +66,7 @@ static HEADER_OPTS header_opts[] = {
     "Resent-Reply-To", HDR_RESENT_REPLY_TO, HDR_OPT_RECIP | HDR_OPT_RR,
     "Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR,
     "Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR,
-    "Return-Path", HDR_RETURN_PATH, HDR_OPT_SENDER,
+    "Return-Path", HDR_RETURN_PATH, HDR_OPT_DROP | HDR_OPT_SENDER,
     "Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_RECIP,
     "Sender", HDR_SENDER, HDR_OPT_SENDER,
     "To", HDR_TO, HDR_OPT_XRECIP,
index e7e7118bf83a6d5a28b7a6ae93ebaec132ec0133..560602d502d13febb403b41eb10f3f90b5d02c49 100644 (file)
@@ -59,7 +59,8 @@
 
 ARGV   *mail_addr_crunch(const char *string, const char *extension)
 {
-    VSTRING *buf = vstring_alloc(100);
+    VSTRING *extern_addr = vstring_alloc(100);
+    VSTRING *canon_addr = vstring_alloc(100);
     ARGV   *argv = argv_alloc(1);
     TOK822 *tree;
     TOK822 **addr_list;
@@ -80,24 +81,25 @@ ARGV   *mail_addr_crunch(const char *string, const char *extension)
     tree = tok822_parse(string);
     addr_list = tok822_grep(tree, TOK822_ADDR);
     for (tpp = addr_list; *tpp; tpp++) {
-       tok822_externalize(buf, tpp[0]->head, TOK822_STR_DEFL);
-       canon_addr_external(buf, STR(buf));
+       tok822_externalize(extern_addr, tpp[0]->head, TOK822_STR_DEFL);
+       canon_addr_external(canon_addr, STR(extern_addr));
        if (extension) {
-           if ((ratsign = strrchr(STR(buf), '@')) == 0) {
-               vstring_strcat(buf, extension);
+           if ((ratsign = strrchr(STR(canon_addr), '@')) == 0) {
+               vstring_strcat(canon_addr, extension);
            } else {
-               VSTRING_SPACE(buf, extlen + 1);
+               VSTRING_SPACE(canon_addr, extlen + 1);
                memmove(ratsign + extlen, ratsign, strlen(ratsign) + 1);
                memcpy(ratsign, extension, extlen);
-               VSTRING_SKIP(buf);
+               VSTRING_SKIP(canon_addr);
            }
        }
-       argv_add(argv, STR(buf), ARGV_END);
+       argv_add(argv, STR(canon_addr), ARGV_END);
     }
     argv_terminate(argv);
     myfree((char *) addr_list);
     tok822_free_tree(tree);
-    vstring_free(buf);
+    vstring_free(canon_addr);
+    vstring_free(extern_addr);
     return (argv);
 }
 
index 02cace24fe213b9da66d4e80eddfe1de2864ff0a..6e58bf0465c309abd841102600afd17b22e695e0 100644 (file)
@@ -44,6 +44,9 @@
 /* .IP MAIL_COPY_DELIVERED
 /*     Prepend a Delivered-To: header with the name of the
 /*     \fIdelivered\fR attribute.
+/* .IP MAIL_COPY_RETURN_PATH
+/*     Prepend a Return-Path: header with the value of the
+/*     \fIsender\fR attribute.
 /* .RE
 /*     The manifest constant MAIL_COPY_MBOX is a convenient shorthand for
 /*     all MAIL_COPY_XXX options that are appropriate for mailbox delivery.
@@ -122,14 +125,21 @@ int     mail_copy(const char *sender, const char *delivered,
     /*
      * Prepend a bunch of headers to the message.
      */
-    if (flags & MAIL_COPY_FROM) {
+    if (flags & (MAIL_COPY_FROM | MAIL_COPY_RETURN_PATH)) {
        if (sender == 0)
            msg_panic("%s: null sender", myname);
-       time(&now);
-       vstream_fprintf(dst, "From %s %s", *sender == 0 ?
-                       MAIL_ADDR_MAIL_DAEMON :
-                       vstring_str(quote_822_local(buf, sender)),
-                       asctime(localtime(&now)));
+       quote_822_local(buf, sender);
+       if (flags & MAIL_COPY_FROM) {
+           time(&now);
+           vstream_fprintf(dst, "From %s %s", *sender == 0 ?
+                           MAIL_ADDR_MAIL_DAEMON :
+                           vstring_str(buf),
+                           asctime(localtime(&now)));
+       }
+       if (flags & MAIL_COPY_RETURN_PATH) {
+           vstream_fprintf(dst, "Return-Path: <%s>\n",
+                           *sender ? vstring_str(buf) : "");
+       }
     }
     if (flags & MAIL_COPY_DELIVERED) {
        if (delivered == 0)
index e25436ae79f41a5c147625c550878eb596a9eaa2..ffa9682f075ea9436018d6df5f9cf936ddd20526 100644 (file)
@@ -27,7 +27,8 @@ extern int mail_copy(const char *, const char *, VSTREAM *, VSTREAM *,
 #define MAIL_COPY_TOFILE       (1<<1)  /* fsync, ftruncate() */
 #define MAIL_COPY_FROM         (1<<2)  /* prepend From_ */
 #define MAIL_COPY_DELIVERED    (1<<3)  /* prepend Delivered-To: */
-#define MAIL_COPY_MBOX         017     /* all turned on */
+#define MAIL_COPY_RETURN_PATH  (1<<4)  /* prepend Return-Path: */
+#define MAIL_COPY_MBOX         (~0)    /* all turned on */
 #define MAIL_COPY_NONE         0       /* all turned off */
 
 /* LICENSE
index 57708702e43c2f265f312c2984dafa9c25d6dc95..94ec5399ada09f654d3302ea065909caf614cac2 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <sys_defs.h>
 #include <time.h>
+#include <stdlib.h>
 
 /* Utility library. */
 
@@ -44,8 +45,9 @@
  /*
   * Application-specific.
   */
-#define DAY_SEC                (24 * HOUR_SEC) /* seconds in a day */
-#define        HOUR_SEC        (60)            /* seconds in an hour */
+#define DAY_MIN                (24 * HOUR_MIN) /* minutes in a day */
+#define        HOUR_MIN        60              /* minutes in an hour */
+#define MIN_SEC                60              /* seconds in a minute */
 
 /* mail_date - return formatted time */
 
@@ -68,18 +70,29 @@ const char *mail_date(time_t when)
     /*
      * POSIX does not require that struct tm has a tm_gmtoff field, so we
      * must compute the time offset from UTC by hand.
+     * 
+     * Starting with the difference in hours/minutes between 24-hour clocks,
+     * adjust for differences in years, in yeardays, and in (leap) seconds.
+     * 
+     * Assume 0..23 hours in a day, 0..59 minutes in an hour. The library spec
+     * has changed: we can no longer assume that there are 0..59 seconds in a
+     * minute.
      */
     gmt = *gmtime(&when);
     lt = localtime(&when);
-    gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_SEC + lt->tm_min - gmt.tm_min;
+    gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_MIN + lt->tm_min - gmt.tm_min;
     if (lt->tm_year < gmt.tm_year)
-       gmtoff -= DAY_SEC;
+       gmtoff -= DAY_MIN;
     else if (lt->tm_year > gmt.tm_year)
-       gmtoff += DAY_SEC;
+       gmtoff += DAY_MIN;
     else if (lt->tm_yday < gmt.tm_yday)
-       gmtoff -= DAY_SEC;
+       gmtoff -= DAY_MIN;
     else if (lt->tm_yday > gmt.tm_yday)
-       gmtoff += DAY_SEC;
+       gmtoff += DAY_MIN;
+    if (lt->tm_sec <= gmt.tm_sec - MIN_SEC)
+       gmtoff -= 1;
+    else if (lt->tm_sec >= gmt.tm_sec + MIN_SEC)
+       gmtoff += 1;
 
     /*
      * First, format the date and wall-clock time. XXX The %e format (day of
@@ -99,10 +112,10 @@ const char *mail_date(time_t when)
     /*
      * Then, add the UTC offset.
      */
-    if (gmtoff < -DAY_SEC || gmtoff > DAY_SEC)
+    if (gmtoff < -DAY_MIN || gmtoff > DAY_MIN)
        msg_panic("UTC time offset %d is larger than one day", gmtoff);
-    vstring_sprintf_append(vp, "%+03d%02d", (int) (gmtoff / HOUR_SEC),
-                          (int) (gmtoff % HOUR_SEC));
+    vstring_sprintf_append(vp, "%+03d%02d", (int) (gmtoff / HOUR_MIN),
+                          (int) (gmtoff % HOUR_MIN));
 
     /*
      * Finally, add the time zone name.
index 7c1ee7cb132f898daaeed73af8b97c611e792ef7..9355c051fe403001ddc6d9acdfa5dc059cafdd4d 100644 (file)
 /*
 /*     The following is a list of implemented names, with the
 /*     corresponding bit masks indicated in parentheses:
-/* .IP "bounce (MAIL_ERROR_BOUNCE)
+/* .IP "bounce (MAIL_ERROR_BOUNCE)"
 /*     A message could not be delivered because it was too large,
 /*     because was sent via too many hops, because the recipient
 /*     does not exist, and so on.
+/* .IP "2bounce (MAIL_ERROR_2BOUNCE)"
+/*     A bounce message could not be delivered.
 /* .IP "policy (MAIL_ERROR_POLICY)"
 /*     Policy violation. This depends on what restrictions have
 /*     been configured locally.
@@ -64,6 +66,8 @@
   */
 NAME_MASK mail_error_masks[] = {
     "bounce", MAIL_ERROR_BOUNCE,
+    "2bounce", MAIL_ERROR_2BOUNCE,
+    "delay", MAIL_ERROR_DELAY,
     "policy", MAIL_ERROR_POLICY,
     "protocol", MAIL_ERROR_PROTOCOL,
     "resource", MAIL_ERROR_RESOURCE,
index 4cb75412abc946c29418cdd0317bdf79af95830d..ffe7b3806cc5819af5b2c6e6982addb9de4e5f83 100644 (file)
@@ -24,6 +24,8 @@
 #define MAIL_ERROR_BOUNCE      (1<<2)
 #define MAIL_ERROR_SOFTWARE    (1<<3)
 #define MAIL_ERROR_RESOURCE    (1<<4)
+#define MAIL_ERROR_2BOUNCE     (1<<5)
+#define MAIL_ERROR_DELAY       (1<<6)
 
 extern NAME_MASK mail_error_masks[];
 
index e5fa32ce75b375601adc2e1078a88e1b7c7e0135..42a48a6ab515e176fd2140eeb71c7b85df000559 100644 (file)
@@ -13,8 +13,8 @@
 /* DESCRIPTION
 /*     This module triggers delivery of backed up mail.
 /*
-/*     mail_flush_deferred() triggers delivery of all mail in the
-/*     deferred queue.
+/*     mail_flush_deferred() triggers delivery of all deferred
+/*     or incoming mail.
 /*
 /*     mail_flush_site() triggers delivery of all mail queued for
 /*     the named site. This routine may degenerate into a
@@ -51,6 +51,7 @@ int     mail_flush_deferred(void)
        QMGR_REQ_FLUSH_DEAD,            /* all hosts, all transports */
        QMGR_REQ_SCAN_ALL,              /* all time stamps */
        QMGR_REQ_SCAN_DEFERRED,         /* scan deferred queue */
+       QMGR_REQ_SCAN_INCOMING,         /* scan incoming queue */
     };
 
     /*
index 189434003b0750611a52bd6fa0d327941212a369..0191de98bd7ad6d7bfe9448e2a88497adde2ff97 100644 (file)
@@ -244,7 +244,7 @@ void    mail_params_init()
     static CONFIG_STR_TABLE other_str_defaults[] = {
        VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, 1, 0,
        VAR_MAIL_OWNER, DEF_MAIL_OWNER, &var_mail_owner, 1, 0,
-       VAR_MYDEST, DEF_MYDEST, &var_mydest, 1, 0,
+       VAR_MYDEST, DEF_MYDEST, &var_mydest, 0, 0,
        VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin, 1, 0,
        VAR_RELAYHOST, DEF_RELAYHOST, &var_relayhost, 0, 0,
        VAR_PROGRAM_DIR, DEF_PROGRAM_DIR, &var_program_dir, 1, 0,
@@ -334,7 +334,7 @@ void    mail_params_init()
     time(&var_starttime);
 
     /*
-     * If have seen this happen just too often.
+     * I have seen this happen just too often.
      */
     if (strcasecmp(var_myhostname, var_relayhost) == 0)
        msg_fatal("myhostname == relayhost");
index f07cb73f11cdae01f06b900bf384939ab7ad7fb2..61978087a671e376e5440e6380b5ffe1c012e85f 100644 (file)
@@ -105,6 +105,10 @@ extern char *var_masq_exceptions;
 #define DEF_RELAYHOST          ""
 extern char *var_relayhost;
 
+#define VAR_FALLBACK_RELAY     "fallback_relay"
+#define DEF_FALLBACK_RELAY     ""
+extern char *var_fallback_relay;
+
 #define VAR_DISABLE_DNS                "disable_dns_lookups"
 #define DEF_DISABLE_DNS                0
 extern bool var_disable_dns;
@@ -176,6 +180,14 @@ extern char *var_db_type;
 #define LOG_FACILITY   LOG_MAIL
 #endif
 
+ /*
+  * Big brother: who receives a blank-carbon copy of all mail that enters
+  * this mail system.
+  */
+#define VAR_ALWAYS_BCC         "always_bcc"
+#define DEF_ALWAYS_BCC         ""
+extern char *var_always_bcc;
+
  /*
   * trivial rewrite/resolve service: mapping tables.
   */
@@ -278,6 +290,17 @@ extern char *var_local_cmd_shell;
 #define DEF_ALIAS_DB_MAP       ALIAS_DB_MAP    /* sys_defs.h */
 extern char *var_alias_db_map;
 
+#define VAR_LUSER_RELAY                "luser_relay"
+#define DEF_LUSER_RELAY                ""
+extern char *var_luser_relay;
+
+ /*
+  * Local delivery: mailbox delivery.
+  */
+#define VAR_MAIL_SPOOL_DIR     "mail_spool_directory"
+#define DEF_MAIL_SPOOL_DIR     _PATH_MAILDIR
+extern char *var_mail_spool_dir;
+
 #define VAR_HOME_MAILBOX       "home_mailbox"
 #define DEF_HOME_MAILBOX       ""
 extern char *var_home_mailbox;
@@ -286,6 +309,21 @@ extern char *var_home_mailbox;
 #define DEF_MAILBOX_COMMAND    ""
 extern char *var_mailbox_command;
 
+#define VAR_MAILBOX_TRANSP     "mailbox_transport"
+#define DEF_MAILBOX_TRANSP     ""
+extern char *var_mailbox_transport;
+
+#define VAR_FALLBACK_TRANSP    "fallback_transport"
+#define DEF_FALLBACK_TRANSP    ""
+extern char *var_fallback_transport;
+
+ /*
+  * Local delivery: path to per-user forwarding file.
+  */
+#define VAR_FORWARD_PATH       "forward_path"
+#define DEF_FORWARD_PATH       "$home/.forward"
+extern char *var_forward_path;
+
 #define VAR_RCPT_DELIM         "recipient_delimiter"
 #define DEF_RCPT_DELIM         ""
 extern char *var_rcpt_delim;
@@ -330,6 +368,10 @@ extern int var_max_backoff_time;
 #define DEF_MAX_QUEUE_TIME     5
 extern int var_max_queue_time;
 
+#define VAR_DELAY_WARN_TIME    "delay_warning_time"
+#define DEF_DELAY_WARN_TIME    0
+extern int var_delay_warn_time;
+
 #define VAR_QMGR_ACT_LIMIT     "qmgr_message_active_limit"
 #define DEF_QMGR_ACT_LIMIT     1000
 
@@ -376,6 +418,13 @@ extern char *var_defer_xports;
 #define DEF_PROC_LIMIT         50
 extern int var_proc_limit;
 
+ /*
+  * Master: default time to wait after service is throttled.
+  */
+#define VAR_THROTTLE_TIME      "service_throttle_time"
+#define DEF_THROTTLE_TIME      60
+extern int var_throttle_time;
+
  /*
   * Any subsystem: default maximum number of clients serviced before a mail
   * subsystem terminates (except queue manager).
@@ -469,6 +518,18 @@ extern int var_smtp_data2_tmout;
 #define DEF_SMTP_QUIT_TMOUT    300
 extern int var_smtp_quit_tmout;
 
+#define VAR_SMTP_SKIP_4XX      "smtp_skip_4xx_greeting"
+#define DEF_SMTP_SKIP_4XX      0
+extern bool var_smtp_skip_4xx_greeting;
+
+#define VAR_IGN_MX_LOOKUP_ERR  "ignore_mx_lookup_error"
+#define DEF_IGN_MX_LOOKUP_ERR  0
+extern bool var_ign_mx_lookup_err;
+
+#define VAR_SKIP_QUIT_RESP     "smtp_skip_quit_response"
+#define DEF_SKIP_QUIT_RESP     1
+extern bool var_skip_quit_resp;
+
  /*
   * SMTP server. The soft error limit determines how many errors an SMTP
   * client may make before we start to slow down; the hard error limit
@@ -643,6 +704,13 @@ extern int var_bad_name_code;
 #define DEF_UNK_NAME_CODE      450
 extern int var_unk_name_code;
 
+#define REJECT_NON_FQDN_HOSTNAME "reject_non_fqdn_hostname"
+#define REJECT_NON_FQDN_SENDER "reject_non_fqdn_sender"
+#define REJECT_NON_FQDN_RCPT   "reject_non_fqdn_recipient"
+#define VAR_NON_FQDN_CODE      "non_fqdn_reject_code"
+#define DEF_NON_FQDN_CODE      504
+extern int var_non_fqdn_code;
+
 #define REJECT_UNKNOWN_ADDRESS "reject_unknown_address"
 #define VAR_UNK_ADDR_CODE      "unknown_address_reject_code"
 #define DEF_UNK_ADDR_CODE      450
index cecdfb31aeb0d18e7de66e6c083654a094256c11..4cde268e7eb4b5591e025168c467f21a6882e852 100644 (file)
@@ -26,6 +26,9 @@
 /*     const char *queue_name;
 /*     const char *queue_id;
 /*
+/*     int     mail_queue_mkdirs(path)
+/*     const char *path;
+/*
 /*     int     mail_queue_rename(queue_id, old_queue, new_queue)
 /*     const char *queue_id;
 /*     const char *old_queue;
 /*     is written to a private buffer that may be overwritten upon the
 /*     next call.
 /*
+/*     mail_queue_mkdirs() creates missing parent directories
+/*     for the file named in \fBpath\fR. A non-zero result means
+/*     that the operation failed.
+/*
 /*     mail_queue_rename() renames a queue file. A non-zero result
 /*     means the operation failed.
 /*
@@ -204,7 +211,7 @@ const char *mail_queue_path(VSTRING *buf, const char *queue_name,
 
 /* mail_queue_mkdirs - fill in missing directories */
 
-static int mail_queue_mkdirs(const char *path)
+int     mail_queue_mkdirs(const char *path)
 {
     char   *myname = "mail_queue_mkdirs";
     char   *saved_path = mystrdup(path);
index f052f4533be662215b7791ec9bacd088411bac5e..acba6a3d0f91705016b6ab785df7a482b6fca738 100644 (file)
@@ -40,6 +40,7 @@ extern int mail_queue_rename(const char *, const char *, const char *);
 extern int mail_queue_remove(const char *, const char *);
 extern const char *mail_queue_dir(VSTRING *, const char *, const char *);
 extern const char *mail_queue_path(VSTRING *, const char *, const char *);
+extern int mail_queue_mkdirs(const char *);
 extern int mail_queue_name_ok(const char *);
 extern int mail_queue_id_ok(const char *);
 
diff --git a/postfix/global/mail_scan_dir.c b/postfix/global/mail_scan_dir.c
new file mode 100644 (file)
index 0000000..f011536
--- /dev/null
@@ -0,0 +1,62 @@
+/*++
+/* NAME
+/*     mail_scan_dir 3
+/* SUMMARY
+/*     mail queue directory scanning support
+/* SYNOPSIS
+/*     #include <mail_scan_dir.h>
+/*
+/*     char    *mail_scan_dir_next(scan)
+/*     SCAN_DIR *scan;
+/* DESCRIPTION
+/*     The \fBmail_scan_dir_next\fR() routine is a wrapper around
+/*     scan_dir_next() that understands the structure of a Postfix
+/*     mail queue.  The result is a queue ID or a null pointer.
+/* SEE ALSO
+/*     scan_dir(3) directory scanner
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <scan_dir.h>
+
+/* Global library. */
+
+#include <mail_scan_dir.h>
+
+/* mail_scan_dir_next - return next queue file */
+
+char   *mail_scan_dir_next(SCAN_DIR *scan)
+{
+    char   *name;
+
+    /*
+     * Exploit the fact that mail queue subdirectories have one-letter names,
+     * so we don't have to stat() every file in sight. This is a win because
+     * many dirent implementations do not return file type information.
+     */
+    for (;;) {
+       if ((name = scan_dir_next(scan)) == 0) {
+           if (scan_dir_pop(scan) == 0)
+               return (0);
+       } else if (strlen(name) == 1) {
+           scan_dir_push(scan, name);
+       } else {
+           return (name);
+       }
+    }
+}
diff --git a/postfix/global/mail_scan_dir.h b/postfix/global/mail_scan_dir.h
new file mode 100644 (file)
index 0000000..fda1326
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _MAIL_SCAN_DIR_H_INCLUDED_
+#define _MAIL_SCAN_DIR_H_INCLUDED_
+
+/*++
+/* NAME
+/*     mail_scan_dir 3h
+/* SUMMARY
+/*     mail directory scanner support
+/* SYNOPSIS
+/*     #include <mail_scan_dir.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <scan_dir.h>
+
+ /*
+  * External interface.
+  */
+extern char *mail_scan_dir_next(SCAN_DIR *);
+
+/* 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/global/mail_version.c b/postfix/global/mail_version.c
new file mode 100644 (file)
index 0000000..e69de29
index b53b9f47da5fa2979d9fb4879252fb4bd3ed9c9e..fb32eac8768c844ac6deedb6a61e9e65e4eb9c03 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Beta-19990122-pl01"
+#define DEF_MAIL_VERSION       "Beta-19990317"
 extern char *var_mail_version;
 
 /* LICENSE
index 6b72e8171f61329fbca68d75266fe69277391fa0..c03aa1dbabc0f8fec892edcb5a99370f858d2d3e 100644 (file)
@@ -46,6 +46,7 @@ REC_TYPE_NAME rec_type_names[] = {
     REC_TYPE_FROM, "sender",
     REC_TYPE_DONE, "done",
     REC_TYPE_RCPT, "recipient",
+    REC_TYPE_WARN, "warning_message_time",
     REC_TYPE_MESG, "message_content",
     REC_TYPE_CONT, "unterminated",
     REC_TYPE_NORM, "normal_data",
@@ -57,7 +58,7 @@ REC_TYPE_NAME rec_type_names[] = {
     0, 0,
 };
 
-/* rec_type_name - map record type ro printable name */
+/* rec_type_name - map record type to printable name */
 
 const char *rec_type_name(int type)
 {
index 3a27f80ec7d57d7d4e5bcdfad4ef9f4326eb0c39..15ad19ee1f866a93bf6bcd3292358dca709016f7 100644 (file)
@@ -31,6 +31,7 @@
 #define REC_TYPE_FROM  'S'             /* sender, required */
 #define REC_TYPE_DONE  'D'             /* delivered recipient, optional */
 #define REC_TYPE_RCPT  'R'             /* todo recipient, optional */
+#define REC_TYPE_WARN  'W'             /* warning message time */
 
 #define REC_TYPE_MESG  'M'             /* start message records */
 
@@ -50,7 +51,7 @@
   * record groups. The first member in each set is the record type that
   * indicates the end of that record group.
   */
-#define REC_TYPE_ENVELOPE      "MCTFSDR"
+#define REC_TYPE_ENVELOPE      "MCTFSDRW"
 #define REC_TYPE_CONTENT       "XLN"
 #define REC_TYPE_EXTRACT       "EDRPre"
 #define REC_TYPE_NOEXTRACT     "E"
   * content size. This is the format of the position field. It is a
   * fixed-width field so it can be updated in place.
   */
-#define REC_TYPE_SIZE_FORMAT   "%9d"   /* content size format */
+#define REC_TYPE_SIZE_FORMAT   "%15ld" /* content size format */
 
  /*
   * The record at the beginning of the message content records specifies the
   * position of the next record group. This is the format of the position
   * field. It is a fixed-width field so it can be updated in place.
   */
-#define REC_TYPE_MESG_FORMAT   "%9d"   /* message length format */
+#define REC_TYPE_MESG_FORMAT   "%15ld" /* message length format */
+
+ /*
+  * The warn record specifies when the next warning that the message
+  * was deferred should be sent.  It is updated in place by qmgr, so
+  * changing this value when there are deferred mesages in the queue
+  * is dangerous!
+  */
+#define REC_TYPE_WARN_FORMAT   "%15ld" /* warning time format */
 
  /*
   * Programmatic interface.
index 605de101315224d4c8046062f4bfdd88acfcdfe0..3c6ef7ce0b7501ade3f7dc92c8cf4b247e14c583 100644 (file)
 
 #include "mail_proto.h"
 #include "mail_params.h"
+#include "clnt_stream.h"
 #include "resolve_clnt.h"
 
 /* Application-specific. */
 
-static VSTREAM *resolve_fp = 0;
-static void resolve_clnt_disconnect(void);
-
-/* resolve_clnt_read - disconnect after EOF */
-
-static void resolve_clnt_read(int unused_event, char *unused_context)
-{
-    resolve_clnt_disconnect();
-}
-
-/* resolve_clnt_time - disconnect after idle timeout */
-
-static void resolve_clnt_time(char *unused_context)
-{
-    resolve_clnt_disconnect();
-}
-
-/* resolve_clnt_disconnect - disconnect from resolve service */
-
-static void resolve_clnt_disconnect(void)
-{
-
-    /*
-     * Be sure to disable read and timer events.
-     */
-    if (msg_verbose)
-       msg_info("resolve service disconnect");
-    event_disable_readwrite(vstream_fileno(resolve_fp));
-    event_cancel_timer(resolve_clnt_time, (char *) 0);
-    (void) vstream_fclose(resolve_fp);
-    resolve_fp = 0;
-}
-
-/* resolve_clnt_connect - connect to resolve service */
-
-static void resolve_clnt_connect(void)
-{
-
-    /*
-     * Register a read event so that we can clean up when the remote side
-     * disconnects, and a timer event so we can cleanup an idle connection.
-     */
-    resolve_fp = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_REWRITE);
-    close_on_exec(vstream_fileno(resolve_fp), CLOSE_ON_EXEC);
-    event_enable_read(vstream_fileno(resolve_fp), resolve_clnt_read, (char *) 0);
-    event_request_timer(resolve_clnt_time, (char *) 0, var_ipc_idle_limit);
-}
+ /*
+  * XXX this is shared with the rewrite client to save a file descriptor.
+  */
+extern CLNT_STREAM *rewrite_clnt_stream;
 
 /* resolve_clnt_init - initialize reply */
 
@@ -136,27 +94,35 @@ void    resolve_clnt_init(RESOLVE_REPLY *reply)
 void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
 {
     char   *myname = "resolve_clnt_query";
+    VSTREAM *stream;
+
+    /*
+     * Sanity check. The result must not clobber the input because we may
+     * have to retransmit the request.
+     */
+#define STR vstring_str
+
+    if (addr == STR(reply->recipient))
+       msg_panic("%s: result clobbers input", myname);
 
     /*
      * Keep trying until we get a complete response. The resolve service is
      * CPU bound; making the client asynchronous would just complicate the
      * code.
      */
-#define STR vstring_str
+    if (rewrite_clnt_stream == 0)
+       rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
+                                 MAIL_SERVICE_REWRITE, var_ipc_idle_limit);
 
     for (;;) {
-       if (resolve_fp == 0)
-           resolve_clnt_connect();
-       else
-           event_request_timer(resolve_clnt_time, (char *) 0,
-                               var_ipc_idle_limit);
-       if (mail_print(resolve_fp, "%s %s", RESOLVE_ADDR, addr)
-           || vstream_fflush(resolve_fp)) {
-           if (msg_verbose || errno != EPIPE)
+       stream = clnt_stream_access(rewrite_clnt_stream);
+       if (mail_print(stream, "%s %s", RESOLVE_ADDR, addr)
+           || vstream_fflush(stream)) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT))
                msg_warn("%s: bad write: %m", myname);
-       } else if (mail_scan(resolve_fp, "%s %s %s", reply->transport,
+       } else if (mail_scan(stream, "%s %s %s", reply->transport,
                             reply->nexthop, reply->recipient) != 3) {
-           if (msg_verbose || errno != EPIPE)
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT))
                msg_warn("%s: bad read: %m", myname);
        } else {
            if (msg_verbose)
@@ -171,7 +137,7 @@ void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
                break;
        }
        sleep(10);                              /* XXX make configurable */
-       resolve_clnt_disconnect();
+       clnt_stream_recover(rewrite_clnt_stream);
     }
 }
 
index 59e225019feeb1906437144f9250baae261f40b8..d6e383577a620bb7317f2c8ccffa5295142d6c70 100644 (file)
 
 #include "mail_proto.h"
 #include "mail_params.h"
+#include "clnt_stream.h"
 #include "rewrite_clnt.h"
 
 /* Application-specific. */
 
-static VSTREAM *rewrite_fp = 0;
-static void rewrite_clnt_disconnect(void);
+ /*
+  * XXX this is shared with the resolver client to save a file descriptor.
+  */
+CLNT_STREAM *rewrite_clnt_stream = 0;
 
-/* rewrite_clnt_read - disconnect after EOF */
-
-static void rewrite_clnt_read(int unused_event, char *unused_context)
-{
-    rewrite_clnt_disconnect();
-}
-
-/* rewrite_clnt_time - disconnect after timeout */
-
-static void rewrite_clnt_time(char *unused_context)
-{
-    rewrite_clnt_disconnect();
-}
-
-/* rewrite_clnt_disconnect - disconnect from rewrite service */
-
-static void rewrite_clnt_disconnect(void)
-{
-
-    /*
-     * Be sure to disable read and timer events.
-     */
-    if (msg_verbose)
-       msg_info("rewrite service disconnect");
-    event_disable_readwrite(vstream_fileno(rewrite_fp));
-    event_cancel_timer(rewrite_clnt_time, (char *) 0);
-    (void) vstream_fclose(rewrite_fp);
-    rewrite_fp = 0;
-}
-
-/* rewrite_clnt_connect - connect to rewrite service */
+/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
 
-static void rewrite_clnt_connect(void)
+VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
 {
+    char   *myname = "rewrite_clnt";
+    VSTREAM *stream;
 
     /*
-     * Register a read event so that we can clean up when the remote side
-     * disconnects, and a timer event so we can cleanup an idle connection.
+     * Sanity check. An address must be in externalized form. The result must
+     * not clobber the input, because we may have to retransmit the query.
      */
-    rewrite_fp = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_REWRITE);
-    close_on_exec(vstream_fileno(rewrite_fp), CLOSE_ON_EXEC);
-    event_enable_read(vstream_fileno(rewrite_fp), rewrite_clnt_read, (char *) 0);
-    event_request_timer(rewrite_clnt_time, (char *) 0, var_ipc_idle_limit);
-}
-
-/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
+#define STR vstring_str
 
-VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
-{
-    char   *myname = "rewrite_clnt";
+    if (*addr == 0)
+       msg_panic("rewrite_clnt: empty address");
+    if (addr == STR(result))
+       msg_panic("rewrite_clnt: result clobbers input");
 
     /*
      * Keep trying until we get a complete response. The rewrite service is
      * CPU bound and making the client asynchronous would just complicate the
      * code.
      */
-#define STR vstring_str
+    if (rewrite_clnt_stream == 0)
+       rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
+                                 MAIL_SERVICE_REWRITE, var_ipc_idle_limit);
 
     for (;;) {
-       if (rewrite_fp == 0)
-           rewrite_clnt_connect();
-       else
-           event_request_timer(rewrite_clnt_time, (char *) 0,
-                               var_ipc_idle_limit);
-       if (mail_print(rewrite_fp, "%s %s %s", REWRITE_ADDR, rule, addr),
-           vstream_fflush(rewrite_fp)) {
-           if (msg_verbose || errno != EPIPE)
+       stream = clnt_stream_access(rewrite_clnt_stream);
+       if (mail_print(stream, "%s %s %s", REWRITE_ADDR, rule, addr),
+           vstream_fflush(stream)) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT))
                msg_warn("%s: bad write: %m", myname);
-       } else if (mail_scan(rewrite_fp, "%s", result) != 1) {
-           if (msg_verbose || errno != EPIPE)
+       } else if (mail_scan(stream, "%s", result) != 1) {
+           if (msg_verbose || (errno != EPIPE && errno != ENOENT))
                msg_warn("%s: bad read: %m", myname);
        } else {
            if (msg_verbose)
@@ -149,7 +117,7 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
                return (result);
        }
        sleep(10);                              /* XXX make configurable */
-       rewrite_clnt_disconnect();
+       clnt_stream_recover(rewrite_clnt_stream);
     }
 }
 
@@ -157,16 +125,18 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
 
 VSTRING *rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
 {
-    VSTRING *temp = vstring_alloc(100);
+    VSTRING *src = vstring_alloc(100);
+    VSTRING *dst = vstring_alloc(100);
 
     /*
      * Convert the address from internal address form to external RFC822
      * form, then rewrite it. After rewriting, convert to internal form.
      */
-    quote_822_local(temp, addr);
-    rewrite_clnt(ruleset, STR(temp), temp);
-    unquote_822_local(result, STR(temp));
-    vstring_free(temp);
+    quote_822_local(src, addr);
+    rewrite_clnt(ruleset, STR(src), dst);
+    unquote_822_local(result, STR(dst));
+    vstring_free(src);
+    vstring_free(dst);
     return (result);
 }
 
index 2715e7b0c532bbf2e50afd4ec9c310f046c6e9d4..f60655d264b699b87a21ad825e9b0b6a6bdde6c6 100644 (file)
@@ -5,7 +5,8 @@ DAEMONS =  bounce.8.html cleanup.8.html defer.8.html local.8.html \
        smtp.8.html smtpd.8.html trivial-rewrite.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
+       postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
+       postsuper.1.html
 CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \
        transport.5.html virtual.5.html
 
@@ -86,6 +87,9 @@ postlog.1.html: ../postlog/postlog.c
 postmap.1.html: ../postmap/postmap.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
+postsuper.1.html: ../postsuper/postsuper.c
+       srctoman $? | nroff -man | man2html | postlink >$@
+
 sendmail.1.html: ../sendmail/sendmail.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
diff --git a/postfix/html/anatomy.html b/postfix/html/anatomy.html
deleted file mode 100644 (file)
index d3e569d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-<html>
-
-<head>
-
-<title>Postfix Mail System Anatomy</title>
-
-</head>
-
-<body>
-
-<h1><a href="big-picture.html"><img src="small-picture.gif" width="115" height="45"></a> Postfix
-Mail System Anatomy</h1>
-
-<hr>
-
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | Postfix Anatomy | <a href="config.html">Postfix
-Configuration</a> | <a href="faq.html">Postfix FAQ</a>
-
-<h2>Table of contents</h2>
-
-<ul>
-
-<li><a href="receiving.html">Receiving mail</a>. What path a
-message takes on its way into the Postfix mail system, and what
-programs are involved. Lots of daemons, mostly.
-
-<p>
-
-<li><a href="delivering.html">Delivering mail</a>. An introduction
-to the machinery that is responsible for delivering mail: queues,
-a queue manager, and more daemons.
-
-<p>
-
-<li><a href="backstage.html">Behind the scenes</a>. What happens
-behind the scenes while mail is flowing through the Postfix system:
-another manager, and still more daemons.
-
-<p>
-
-<li><a href="commands.html">Command-line utilities</a>. Auxiliary
-programs that people interact with when using the Postfix mail
-system. No daemons here.
-
-</ul>
-
-<hr>
-
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | Postfix Anatomy | <a href="config.html">Postfix
-Configuration</a> | <a href="faq.html">Postfix FAQ</a>
-
-</body>
-
-</html>
index 82eea2515f08602f00c418c414042445d52f27ac..33fc45cc18725119fbdba4de590059d2e1661e25 100644 (file)
@@ -13,7 +13,7 @@ Overview - Global Architecture</h1>
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | Global architecture | <a href="queuing.html">Queue
 Management</a> | <a href="security.html">Security</a>
@@ -102,7 +102,7 @@ it has been standard practice for years in many places.
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | Global architecture | <a href="queuing.html">Queue
 Management</a> | <a href="security.html">Security</a>
index 1cacf5b21b5b8037eece45dea70135ef754cab99..5ce551c0427d541510ef5e1fc4d8fa1d65df2a47 100644 (file)
@@ -13,7 +13,7 @@ Anatomy - Behind the Scenes</h1>
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | <a
 href="delivering.html">Delivering Mail</a> | Behind the Scenes |
 <a href="commands.html">Command-line Utilities</a>
@@ -61,7 +61,7 @@ href="mailq.1.html">mailq</a> command.
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | <a
 href="delivering.html">Delivering Mail</a> | Behind the Scenes |
 <a href="commands.html">Command-line Utilities</a>
index 60b195f9f6b9337bf053339b8e5cc68c9dad1e0b..19635f6f9bc32d4b9f71b3c7bb81515c088982c2 100644 (file)
@@ -12,7 +12,7 @@
 
 <hr>
 
-<a href="config.html">Up one level</a> | Basic Configuration | <a
+<a href="index.html">Up one level</a> | Basic Configuration | <a
 href="uce.html">UCE Controls</a> | <a href="rate.html"> Rate
 Controls</a> | <a href="resource.html"> Resource Controls</a> | <a
 href="rewrite.html"> Address Manipulation </a>
@@ -177,7 +177,7 @@ report only serious problems (resource, software) to postmaster:
 
 <dl>
 
-<dt> Example:
+<dt> Default:
 
 <dd> <b>notify_classes = resource, software</b>
 
@@ -189,9 +189,23 @@ report only serious problems (resource, software) to postmaster:
 
 <dl>
 
-<dt> <b>bounce</b> <dd> Inform the postmaster of undeliverable
-mail.  For privacy reasons, the postmaster receives the message
-headers only.
+<dt> <b>bounce</b> <dd> Send postmaster copies of undeliverable
+mail.  If mail is undeliverable, a so-called single bounce message
+is sent, with a copy of the message that was not delivered. For
+privacy reasons, the postmaster copy of a single bounce message is
+truncated after the original message headers.  If a single bounce
+message is undeliverable, the postmaster receives a double bounce
+message with a copy of the entire single bounce message.  See also
+the <a href="rewrite.html#luser_relay"> luser_relay</a> feature.
+
+<p>
+
+<dt> <b>2bounce</b> <dd> Send double bounces to the postmaster.
+
+<p>
+
+<dt> <b>delay</b> <dd> Inform the postmaster of delayed mail.
+In this case, the postmaster receives message headers only.
 
 <p>
 
@@ -333,7 +347,7 @@ on the virtual interfaces or you would have a mailer loop.
 
 <hr>
 
-<a href="config.html">Up one level</a> | Basic Configuration | <a
+<a href="index.html">Up one level</a> | Basic Configuration | <a
 href="uce.html">UCE Controls</a> | <a href="rate.html"> Rate
 Controls</a> | <a href="resource.html"> Resource Controls</a> | <a
 href="rewrite.html"> Address Manipulation </a>
index 10d89c3b2b071b4a123debbfb41696cecbb5e861..5d33e2748024ffe73529a06ac371ffb56d77badd 100644 (file)
@@ -19,7 +19,7 @@
 
 The figure shows the main Postfix system components, and the main
 information flows between them. Postfix system components are
-introduced in the <a href="anatomy.html">Postfix anatomy</a>
+introduced in the <a href="receiving.html">Postfix anatomy</a>
 documentation.
 
 <p>
index b250e9ccbe48591a815a4187a289b3ef94a2fdc1..0b1e5ce63e9ef70bbbafa4f711d0772bae783e22 100644 (file)
@@ -13,7 +13,7 @@ Anatomy - Command-line Utilities</h1>
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | <a
 href="delivering.html">Delivering Mail</a> | <a
 href="backstage.html">Behind the Scenes</a> | Command-line Utilities
@@ -89,11 +89,18 @@ Postfix lookup tables such as <a href="canonical.5.html">canonical</a>,
 <a href="virtual.5.html">virtual</a> and others. It is a cousin of
 the UNIX <b>makemap</b> command.
 
+<p>
+
+<li>The <a href="postsuper.1.html">postsuper</a> command maintains
+the Postfix queue. It removes old temporary files, and moves queue
+files into the right directory after a change in the hashing depth
+of queue directories. This command is run at mail system startup time.
+
 </ul>
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | <a
 href="delivering.html">Delivering Mail</a> | <a
 href="backstage.html">Behind the Scenes</a> | Command-line Utilities
diff --git a/postfix/html/config.html b/postfix/html/config.html
deleted file mode 100644 (file)
index 2566ed1..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<html>
-
-<head>
-
-<title> Postfix Mail System Configuration </title>
-
-</head>
-
-<body>
-
-<h1><a href="big-picture.html"><img src="small-picture.gif" width="115" height="45"></a> Postfix Mail System Configuration </h1>
-
-<hr>
-
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | <a href="anatomy.html">Postfix Anatomy</a> | Postfix
-Configuration | <a href="faq.html">Postfix FAQ</a>
-
-<p>
-
-<h2> Table of contents </h2>
-
-<ul>
-
-<li> <a href="basic.html">Basic configuration</a>. All you need
-to know about Postfix for the most common types of installation,
-assuming that you are already familiar with sendmail aliases and
-forwarding.
-
-<p>
-
-<li> <a href="uce.html">UCE controls</a>. A description of the
-Postfix mechanisms to reject unwanted mail, a.k.a. UCE, and to
-restrict unauthorized mail relaying.
-
-<p>
-
-<li> <a href="rate.html">Rate controls</a>. How to achieve
-performance without hosing your system or your neighbor's systems,
-and how to deal with broken or malicious client programs.
-
-<p>
-
-<li>
-
-<a href="resource.html">Resource controls</a>. How to set Postfix
-memory and file system resource budgets, and how to deal with
-temporary problems.
-
-<p>
-
-<li> <a href="rewrite.html">Address manipulation</a>. How to do
-address rewriting, message routing, and message transport selection
-without ever having to use an address rewriting language. This
-section covers aliases and virtual domains as well.
-
-</ul>
-
-<hr>
-
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | <a href="anatomy.html">Postfix Anatomy</a> | Postfix
-Configuration | <a href="faq.html">Postfix FAQ</a>
-
-</body>
-
-</html>
index 9fc2296e2aed9d2285322bcc277182cbbf4f409a..12036a192ebe66bf074879738c7e237a0030499f 100644 (file)
@@ -13,7 +13,7 @@ Anatomy - Delivering Mail</h1>
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | Delivering Mail | <a
 href="backstage.html">Behind the Scenes</a> | <a
 href="commands.html">Command-line Utilities</a>
@@ -129,7 +129,7 @@ addresses.
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="receiving.html">Receiving Mail</a> | Delivering Mail | <a
 href="backstage.html">Behind the Scenes</a> | <a
 href="commands.html">Command-line Utilities</a>
index 3e38aa5bbe20363e2ec9b798018353c66821fee9..512b9701eeb52aa58ddfa50592afafd060560574 100644 (file)
@@ -14,9 +14,7 @@
 
 <hr>
 
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | <a href="anatomy.html">Postfix Anatomy</a> | <a
-href="config.html">Postfix Configuration</a> | Postfix FAQ
+<a href="index.html">Up one level</a> | Postfix FAQ
 
 <h2>Table of contents</h2>
 
@@ -26,6 +24,8 @@ href="config.html">Postfix Configuration</a> | Postfix FAQ
 
 <li><a href="#firewall">Running Postfix on a firewall</a>
 
+<li><a href="#local">Delivering some users locally while sending mail as user@domain</a>
+
 <li><a href="#maildir">Support for maildir-style mailboxes</a>
 
 <li><a href="#procmail">Using Procmail for local delivery</a>
@@ -40,6 +40,10 @@ href="config.html">Postfix Configuration</a> | Postfix FAQ
 
 <li><a href="#uucp-only">Using UUCP as the default transport</a>
 
+<li><a href="#fax">Sending mail to a FAX machine</a>
+
+<li><a href="#bind">Undefined symbols: ___dn_expand, ___res_init etc.</a>
+
 <li><a href="#db">Using DB libraries on Solaris etc.</a>
 
 </ul>
@@ -87,9 +91,54 @@ specify the gateway host itself:
 <p>
 
 <li>If you want to deliver internal mail directly without going through
-the intranet mail gateway, you have to specify a routing entry in the
-<a href="transport.5.html">transport</a> table, and you have to
-enable <a href="transport.5.html">transport</a> table lookups.
+the intranet mail gateway, there are two possibilities.
+
+<p>
+
+<ol>
+
+<li>Specify the intranet mail gateway as the fall-back relay for
+all mail with an unknown or unreachable destination:
+
+<p>
+
+<dl>
+
+<dl>
+
+<dt>main.cf:
+
+<dd><b>fallback_relay = $mydomain</b>
+
+</dl>
+
+<p>
+
+This assumes that your organization has set up multiple internal
+MX hosts for the local domain.
+
+<p>
+
+If your intranet does not use MX records internally, you have to
+specify the gateway host itself:
+
+<p>
+
+<dl>
+
+<dt>main.cf:
+
+<dd><b>fallback_relay = </b><i>gateway.my.domain</i>
+
+</dl>
+
+</dl>
+
+<p>
+
+<li>Specify routing information for the local domain in the <a
+href="transport.5.html">transport</a> table, and enable <a
+href="transport.5.html">transport</a> table lookups.
 
 <p>
 
@@ -107,6 +156,8 @@ enable <a href="transport.5.html">transport</a> table lookups.
 
 <dd><i>my.domain</i> &nbsp; <b>smtp</b>:
 
+<dd><i>.my.domain</i> &nbsp; <b>smtp</b>:
+
 </dl>
 
 </dl>
@@ -116,6 +167,8 @@ enable <a href="transport.5.html">transport</a> table lookups.
 Specify <b>dbm:/etc/postfix/transport</b> if your system
 uses <b>dbm</b> files instead of <b>db</b>.
 
+</ol>
+
 <p>
 
 <li>Execute the command <b>postfix reload</b> to make the
@@ -187,6 +240,67 @@ that table is ignored for destinations that match <b>$mydestination</b>.
 That's an implementation error, and it will be removed.
 
 
+<hr>
+
+<a name="local"><h2>Delivering some users locally while sending mail as user@domain</h2></a>
+
+<ul>
+
+<li>In order to send mail as <i>user@domain</i>, edit
+<b>/etc/postfix/main.cf</b> and specify that the local domain
+is to be appended to addresses that do not have a domain:
+
+<p>
+
+<dl>
+
+<dd><b>myorigin = </b><i>$mydomain</i>
+
+</dl>
+
+<p>
+
+<li>In order to receive some users locally, such as <b>root</b> or
+<b>postmaster</b>,
+
+<p>
+
+<ul>
+
+<li>edit <b>/etc/postfix/main.cf</b> and specify a virtual lookup table:
+
+<p>
+
+<dl>
+
+<dd><b>virtual_maps = hash:/etc/postfix/virtual</b>
+
+</dl>
+
+<p>
+
+<li>edit <b>/etc/postfix/virtual</b> and specify non-default destinations:
+
+<p>
+
+<dl>
+
+<dd><b>root &nbsp; root@</b><i>my.host.name</i>
+
+<dd><b>postmaster &nbsp; postmaster@</b><i>my.host.name</i>
+
+</dl>
+
+</ul>
+
+<p>
+
+<li>Execute the command <b>postmap /etc/postfix/virtual</b> to
+update the table, and <b>postfix reload</b> to make the changes
+effective.
+
+</ul>
+
 <hr>
 
 <a name="maildir"><h2>Support for maildir-style mailboxes</h2> </a>
@@ -448,6 +562,70 @@ changes effective.
 
 </ul>
 
+<hr>
+
+<a name="fax"><h2>Sending mail to a FAX machine</h2></a>
+
+The following information is by Joerg Henne:
+
+<p>
+Over here we are using the scheme <fax number>@fax.our.domain with Postfix and
+HylaFax. Here's the setup used:
+
+<p>
+In master.cf:
+
+<p>
+
+<pre>
+    fax       unix  -       n       n       -       -       pipe
+       flags= user=fax argv=/usr/bin/faxmail -d -n ${user}
+</pre>
+
+<p>
+
+In the transports map:
+
+<p>
+
+<pre>
+    fax.your.domain   fax:localhost
+</pre>
+
+<p>
+
+Note: be sure to not advertise <b>fax.your.domain</b> in the DNS...
+
+<hr>
+
+<a name="bind"><h2>Undefined symbols: ___dn_expand, ___res_init etc.</h2></a>
+
+Question: When I build Postfix I get the following errors:
+
+<p>
+
+<pre>
+    ld: Undefined symbol
+       ___dn_expand
+       ___res_init
+       ___res_search
+    *** Error code 1
+</pre>
+
+<p>
+
+Answer: you're mixing BIND version 8 include files with a
+different version of the resolver library. 
+
+<p>
+
+Fix: use the right include files. For example: 
+
+<p>
+
+<pre>
+    <tt>make makefiles CCARGS="-I/usr/include"</tt>.
+</pre>
 
 <hr>
 
@@ -469,16 +647,23 @@ version</a> which has a db-1.85 compatible interface.
 
 <p>
 
-Use the following commands in the Postfix top-level directory:
+Use the following commands in the Postfix top-level directory.
+The LD_LIBRARY_PATH unsets may be required to avoid linking in the
+wrong libraries.
 
 <dl>
 
-<dd>% <b>make tidy</b>
+<dd>% <tt>LD_LIBRARY_PATH= </tt> &nbsp <i>(Bourne-shell syntax)</i>
+
+<dd>% <tt>unsetenv LD_LIBRARY_PATH </tt> &nbsp <i>(C-shell syntax)</i>
+
+<dd>% <tt>make tidy</tt>
 
-<dd>% <b>make makefiles CCARGS="-DHAS_DB
--I</b><i>/some/where/include</i><b>" AUXLIBS=</b><i>/some/where/libdb.a</i>
+<dd>% <tt>make makefiles CCARGS="-DHAS_DB -DPATH_DB_H='&lt;db_185.h&gt;'
+-I</tt><i>/some/where/include</i><tt>" 
+AUXLIBS=</tt><i>/some/where/libdb.a</i>
 
-<dd>% <b>make</b>
+<dd>% <tt>make</tt>
 
 </dl>
 
@@ -496,9 +681,7 @@ to get rid of the bogus file, or the linker will fail to find
 
 <hr>
 
-<a href="index.html">Up one level</a> | <a href="overview.html">Postfix
-Overview</a> | <a href="anatomy.html">Postfix Anatomy</a> | <a
-href="config.html">Postfix Configuration</a> | Postfix FAQ
+<a href="index.html">Up one level</a> | Postfix FAQ
 
 </body>
 
index ec019edd8edeb6d5be521eba516f35bb13307080..1b8436d527aa42de66064f74c338d6e229ed28b2 100644 (file)
@@ -13,7 +13,7 @@ Overview - Goals and Features</h1>
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | Goals and features | <a
 href="architecture.html">Global architecture</a> | <a
 href="queuing.html">Queue Management</a> | <a
@@ -121,7 +121,7 @@ support for other lookup mechanisms is relatively easy.
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | Goals and features | <a
 href="architecture.html">Global architecture</a> | <a
 href="queuing.html">Queue Management</a> | <a
index 69ef506e68e7820be752dd1319c87fbecfc678ca..9282ad42dbd83a59494ebfb3199c46b22d965cfc 100644 (file)
@@ -2,48 +2,50 @@
 
 <head>
 
-<title>Postfix Mail System Documentation</title>
+<title>Wietse's Postfix Project</title>
 
 </head>
 
 <body>
 
-<h1><a href="big-picture.html"><img src="small-picture.gif" width="115" height="45"></a> Postfix Mail System Documentation</h1>
+<h1><a href="big-picture.html"><img src="small-picture.gif" width="115"
+height="45"></a> Wietse's Postfix Project</h1>
 
 <hr>
 
-<h2>Table of contents</h2>
+<a href="motivation.html">Postfix Overview</a> | <a
+href="receiving.html">Postfix Anatomy</a> | <a href="basic.html">Postfix
+Configuration</a> | <a href="faq.html">Postfix FAQ</a>
 
-<ul>
+<p>
 
-<li><a href="overview.html">Postfix Overview</a>. A gentle introduction
-to the Postfix mail system.
+<blockquote><i> All programmers are optimists </i> -- Frederick P.
+Brooks, Jr.  </blockquote>
 
 <p>
 
-<li><a href="anatomy.html">Postfix Anatomy</a>. The programs that
-make up the Postfix mail system, and how mail flows through it.
+First of all, thank you for your interest in the Postfix project.
 
 <p>
 
-<li><a href="config.html">Postfix Configuration</a>. How to configure
-the system, from the very basic to the very advanced.
+What is Postfix? It is Wietse Venema's attempt to provide an
+alternative to the widely-used <a
+href="http://www.sendmail.org/">Sendmail</a> program.  Sendmail is
+responsible for an estimated 70% of all e-mail delivered on the
+Internet.  With an estimated 100 million users, that's billions of
+messages daily.  A stunning number.
 
 <p>
 
-<li><a href="faq.html">Postfix FAQ</a>. Look here for quick answers
-to common questions.
-
-</ul>
+Postfix attempts to be fast, easy to administer, and secure, while
+at the same time being sendmail compatible enough to not upset
+existing users.
 
 <hr>
 
-<ul>
-
-<li><a href="http://www.porcupine.org/wietse/">About the author</a>.
-The author of TCP Wrapper, co-author of SATAN, and other software.
-
-<li>
+<a href="motivation.html">Postfix Overview</a> | <a
+href="receiving.html">Postfix Anatomy</a> | <a href="basic.html">Postfix
+Configuration</a> | <a href="faq.html">Postfix FAQ</a>
 
 </body>
 
index f7b0aebb49660507cfcc16286de7826d0ebc8aca..dbc3cffcc413d8746f293791fb0166a709991ffc 100644 (file)
@@ -77,29 +77,46 @@ LOCAL(8)                                                 LOCAL(8)
        listed in a <b>Delivered-To:</b> header, the message is  bounced.
 
 <b>MAILBOX</b> <b>DELIVERY</b>
-       The  per-user mailbox is either a file in the default UNIX
-       mailbox directory (<b>/var/mail/</b><i>user</i> or <b>/var/spool/mail/</b><i>user</i>)
-       or  it  is a file in the user's home directory with a name
-       specified via the  <b>home</b><i>_</i><b>mailbox</b>  configuration  parameter.
-       Specify  a  path  name  ending  in  <b>/</b> for <b>qmail</b>-compatible
-       <b>maildir</b> delivery.  Mailbox delivery can be delegated to an
-       external  command  specified with the <b>mailbox</b><i>_</i><b>command</b> con-
-       figuration parameter.
+       The  default  per-user  mailbox is a file in the UNIX mail
+       spool directory (<b>/var/mail/</b><i>user</i> or  <b>/var/spool/mail/</b><i>user</i>);
+       the  location  can be specified with the <b>mail</b><i>_</i><b>spool</b><i>_</i><b>direc-</b>
+       <b>tory</b> configuration parameter.
+
+       Alternatively, the per-user mailbox can be a file  in  the
+       user's  home  directory  with  a  name  specified  via the
+       <b>home</b><i>_</i><b>mailbox</b> configuration parameter. Specify  a  relative
+       path name. Specify a name ending in <b>/</b> for <b>qmail</b>-compatible
+       <b>maildir</b> delivery.
 
-       The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
-       lope  header  to  each  message,  prepends a <b>Delivered-To:</b>
-       header with the envelope recipient address, prepends  a  &gt;
-       character  to lines beginning with "<b>From</b> ", and appends an
-       empty line.  The envelope sender address is  available  in
-       the <b>Return-Path:</b> header.  The mailbox is locked for exclu-
-       sive access while delivery is  in  progress.  In  case  of
-       problems,  an  attempt  is made to truncate the mailbox to
-       its original length.
+       Mailbox delivery can be delegated to an  external  command
+       specified  with  the <b>mailbox</b><i>_</i><b>command</b> configuration parame-
+       ter. The command  executes  with  the  privileges  of  the
+       recipient  user  (exception:  in case of delivery as root,
+       the command executes with the privileges of <b>default</b><i>_</i><b>user</b>).
+
+       Mailbox  delivery  can be delegated to alternative message
+       transports specified in the  <b>master.cf</b>  file.   The  <b>mail-</b>
+       <b>box</b><i>_</i><b>transport</b>  configuration parameter specifies a message
+       transport that is to be used  for  all  local  recipients,
+       regardless  of  whether  they are found in the UNIX passwd
+       database.  The <b>fallback</b><i>_</i><b>transport</b>  parameter  specifies  a
+       message transport for recipients that are not found in the
+       UNIX passwd database.
+
+       In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
+       mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to
+       each message, prepends a  <b>Delivered-To:</b>  header  with  the
+       envelope recipient address, prepends a <b>Return-Path:</b> header
+       with the envelope sender address, prepends a  &gt;  character
+       to  lines  beginning  with  "<b>From</b>  ", and appends an empty
+       line.  The mailbox is locked for  exclusive  access  while
+       delivery  is  in progress. In case of problems, an attempt
+       is made to truncate the mailbox to its original length.
 
        In the case of <b>maildir</b> delivery, the local daemon prepends
-       a   <b>Delivered-To:</b>   header  with  the  envelope  recipient
-       address.  The envelope sender address is available in  the
-       <b>Return-Path:</b> header.
+       a <b>Delivered-To:</b> header with the envelope recipient address
+       and prepends  a  <b>Return-Path:</b>  header  with  the  envelope
+       sender address.
 
 <b>EXTERNAL</b> <b>COMMAND</b> <b>DELIVERY</b>
        The    <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>    configuration   parameter
@@ -107,10 +124,22 @@ LOCAL(8)                                                 LOCAL(8)
        ting  (<b>alias,</b>  <b>forward</b>)  forbids  command  destinations in
        <b>:include:</b> files.
 
-       The command is executed directly  where  possible.  Assis-
-       tance  by the shell (<b>/bin/sh</b> on UNIX systems) is used only
-       when the command contains shell magic characters, or  when
-       the command invokes a shell built-in command.
+       The  command  is   executed   directly   where   possible.
+
+
+
+                                                                2
+
+
+
+
+
+LOCAL(8)                                                 LOCAL(8)
+
+
+       Assistance  by the shell (<b>/bin/sh</b> on UNIX systems) is used
+       only when the command contains shell magic characters,  or
+       when the command invokes a shell built-in command.
 
        A  limited  amount  of command output (standard output and
        standard error) is captured for inclusion with  non-deliv-
@@ -125,25 +154,13 @@ LOCAL(8)                                                 LOCAL(8)
        dependent default path, and the <b>TZ</b> (time zone) environment
        variable is always passed on without change.
 
-
-
-
-                                                                2
-
-
-
-
-
-LOCAL(8)                                                 LOCAL(8)
-
-
        The current working directory is the mail queue directory.
 
        The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve-
        lope header to  each  message,  prepends  a  <b>Delivered-To:</b>
-       header with the recipient envelope address, and appends an
-       empty line.  The envelope sender address is  available  in
-       the <b>Return-Path:</b> header.
+       header  with  the  recipient  envelope address, prepends a
+       <b>Return-Path:</b> header with the sender envelope address,  and
+       appends an empty line.
 
 <b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b>
        The  <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts
@@ -174,6 +191,18 @@ LOCAL(8)                                                 LOCAL(8)
 
        For example, with  "<b>recipient</b><i>_</i><b>delimiter</b>  <b>=</b>  <b>+</b>",  mail  for
        <i>name</i>+<i>foo</i>  is  delivered  to  the  alias <i>name</i>+<i>foo</i> or to the
+
+
+
+                                                                3
+
+
+
+
+
+LOCAL(8)                                                 LOCAL(8)
+
+
        alias <i>name</i>, to  the  destinations  listed  in  ~<i>name</i>/.<b>for-</b>
        <b>ward</b>+<i>foo</i> or in ~<i>name</i>/.<b>forward</b>, to the mailbox owned by the
        user <i>name</i>, or it is sent back as undeliverable.
@@ -190,19 +219,6 @@ LOCAL(8)                                                 LOCAL(8)
        superuser, delivery is made with the rights specified with
        the <b>default</b><i>_</i><b>privs</b> configuration parameter.
 
-
-
-
-
-                                                                3
-
-
-
-
-
-LOCAL(8)                                                 LOCAL(8)
-
-
 <b>STANDARDS</b>
        RFC 822 (ARPA Internet Text Messages)
 
@@ -236,20 +252,24 @@ LOCAL(8)                                                 LOCAL(8)
        <b>alias</b><i>_</i><b>maps</b>
               List of alias databases.
 
-       <b>home</b><i>_</i><b>mailbox</b>
-              Pathname of a mailbox relative  to  a  user's  home
-              directory.  Specify a path ending in <b>/</b> for maildir-
-              style delivery.
-
        <b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
               Shell to use for external  command  execution  (for
               example,  /some/where/smrsh  -c).   When a shell is
               specified, it is invoked even when the command con-
-              tains  no  shell  built-in commands or meta charac-
-              ters.
+              tains   no   shell   built-in   commands   or  meta
+
+
+
+                                                                4
+
+
+
 
-       <b>mailbox</b><i>_</i><b>command</b>
-              External command to use for mailbox delivery.
+
+LOCAL(8)                                                 LOCAL(8)
+
+
+              characters.
 
        <b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b>
               Give special treatment to <b>owner-</b><i>xxx</i> and <i>xxx</i><b>-request</b>
@@ -258,93 +278,128 @@ LOCAL(8)                                                 LOCAL(8)
        <b>recipient</b><i>_</i><b>delimiter</b>
               Separator between username and address extension.
 
+<b>Mailbox</b> <b>delivery</b>
+       <b>fallback</b><i>_</i><b>transport</b>
+              Message transport for recipients that are not found
+              in the UNIX passwd database.  This parameter  over-
+              rides <b>luser</b><i>_</i><b>relay</b>.
 
+       <b>home</b><i>_</i><b>mailbox</b>
+              Pathname  of  a  mailbox  relative to a user's home
+              directory.  Specify a path ending in <b>/</b> for maildir-
+              style delivery.
 
-                                                                4
-
-
-
+       <b>luser</b><i>_</i><b>relay</b>
+              Destination  (<i>@domain</i>  or <i>address</i>) for non-existent
+              users.  The <i>address</i> can be any destination that  is
+              valid in an alias file.
 
+       <b>mail</b><i>_</i><b>spool</b><i>_</i><b>directory</b>
+              Directory  with  UNIX-style  mailboxes. The default
+              pathname is system dependent.
 
-LOCAL(8)                                                 LOCAL(8)
+       <b>mailbox</b><i>_</i><b>command</b>
+              External command to use for mailbox  delivery.  The
+              command  executes  with  the  recipient  privileges
+              (exception: root).
 
+       <b>mailbox</b><i>_</i><b>transport</b>
+              Message transport to use for  mailbox  delivery  to
+              all local recipients, whether or not they are found
+              in the UNIX passwd database.  This parameter  over-
+              rides  all other configuration parameters that con-
+              trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>.
 
 <b>Locking</b> <b>controls</b>
        <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
-              Limit  the  number of attempts to acquire an exclu-
+              Limit the number of attempts to acquire  an  exclu-
               sive lock on a mailbox or external file.
 
        <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
-              Time in  seconds  between  successive  attempts  to
+              Time  in  seconds  between  successive  attempts to
               acquire an exclusive lock.
 
        <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
               Limit the time after which a stale lock is removed.
 
+
+
+
+
+                                                                5
+
+
+
+
+
+LOCAL(8)                                                 LOCAL(8)
+
+
 <b>Resource</b> <b>controls</b>
        <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>
-              Limit the amount of time for delivery  to  external
+              Limit  the  amount of time for delivery to external
               command.
 
        <b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
-              Limit  the size of the duplicate filter for results
+              Limit the size of the duplicate filter for  results
               from alias etc. expansion.
 
        <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
-              Limit the amount of memory used  for  processing  a
+              Limit  the  amount  of memory used for processing a
               partial input line.
 
        <b>local</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
               Limit the number of parallel deliveries to the same
-              user.   The  default  limit  is  taken   from   the
+              user.    The   default  limit  is  taken  from  the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
 
        <b>local</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  the  number of recipients per message deliv-
-              ery.   The  default  limit  is   taken   from   the
+              Limit the number of recipients per  message  deliv-
+              ery.    The   default   limit  is  taken  from  the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
 
 <b>Security</b> <b>controls</b>
        <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
-              Restrict  the  usage  of  mail delivery to external
+              Restrict the usage of  mail  delivery  to  external
               command.
 
        <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b>
-              Restrict the usage of  mail  delivery  to  external
+              Restrict  the  usage  of  mail delivery to external
               file.
 
        <b>default</b><i>_</i><b>privs</b>
-              Default  rights  for  delivery  to external file or
+              Default rights for delivery  to  external  file  or
               command.
 
 <b>HISTORY</b>
-       The <b>Delivered-To:</b> header appears in the  <b>qmail</b>  system  by
+       The  <b>Delivered-To:</b>  header  appears in the <b>qmail</b> system by
        Daniel Bernstein.
 
-       The  <i>maildir</i>  structure  appears  in  the  <b>qmail</b> system by
+       The <i>maildir</i> structure  appears  in  the  <b>qmail</b>  system  by
        Daniel Bernstein.
 
+<b>SEE</b> <b>ALSO</b>
+       <a href="aliases.5.html">aliases(5)</a> format of alias database
+       <a href="bounce.8.html">bounce(8)</a> non-delivery status reports
+       <a href="postalias.1.html">postalias(1)</a> create/update alias database
+       syslogd(8) system logging
+       <a href="qmgr.8.html">qmgr(8)</a> queue manager
 
+<b>LICENSE</b>
+       The  Secure  Mailer  license must be distributed with this
+       software.
 
-                                                                5
 
 
 
+                                                                6
 
 
-LOCAL(8)                                                 LOCAL(8)
 
 
-<b>SEE</b> <b>ALSO</b>
-       <a href="aliases.5.html">aliases(5)</a> format of alias database
-       <a href="bounce.8.html">bounce(8)</a> non-delivery status reports
-       <a href="postalias.1.html">postalias(1)</a> create/update alias database
-       syslogd(8) system logging
-       <a href="qmgr.8.html">qmgr(8)</a> queue manager
 
-<b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
-       software.
+LOCAL(8)                                                 LOCAL(8)
+
 
 <b>AUTHOR(S)</b>
        Wietse Venema
@@ -392,7 +447,18 @@ LOCAL(8)                                                 LOCAL(8)
 
 
 
-                                                                6
+
+
+
+
+
+
+
+
+
+
+
+                                                                7
 
 
 </pre> </body> </html>
index 2f7ebabc49bb2e35b44459da1a3818376b0df5e7..c93f0ce9cc754107fd74b41015e1a6aeffd6f1f4 100644 (file)
@@ -139,6 +139,10 @@ MASTER(8)                                               MASTER(8)
 
               child process.
 
+       <b>service</b><i>_</i><b>throttle</b><i>_</i><b>time</b>
+              Time to avoid forking a server that appears  to  be
+              broken.
+
 <b>FILES</b>
        /etc/postfix/main.cf: global configuration file.
        /etc/postfix/master.cf: master process configuration file.
@@ -150,7 +154,7 @@ MASTER(8)                                               MASTER(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -185,10 +189,6 @@ MASTER(8)                                               MASTER(8)
 
 
 
-
-
-
-
 
 
 
index 9eccb0923dded20065733a7f6ecac9fa2a45ad73..f27c9569adb820b9de3efec12743b9bbdb880b31 100644 (file)
@@ -13,7 +13,7 @@ Overview - Introduction</h1>
 
 <hr>
 
-<a href="overview.html">Up one level</a> | Introduction | <a
+<a href="index.html">Up one level</a> | Introduction | <a
 href="goals.html">Goals and features</a> | <a
 href="architecture.html">Global architecture</a> | <a
 href="queuing.html">Queue Management</a> | <a
@@ -49,7 +49,7 @@ that friendly competition will help to improve both programs.
 
 <hr>
 
-<a href="overview.html">Up one level</a> | Introduction | <a
+<a href="index.html">Up one level</a> | Introduction | <a
 href="goals.html">Goals and features</a> | <a
 href="architecture.html">Global architecture</a> | <a
 href="queuing.html">Queue Management</a> | <a
diff --git a/postfix/html/overview.html b/postfix/html/overview.html
deleted file mode 100644 (file)
index 9eea539..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<html>
-
-<head>
-
-<title>Postfix Mail System Overview</title>
-
-</head>
-
-<body>
-
-<h1><a href="big-picture.html"><img src="small-picture.gif" width="115" height="45"></a> Postfix
-Mail System Overview</h1>
-
-<hr>
-
-<a href="index.html">Up one level</a> | Postfix Overview | <a
-href="anatomy.html">Postfix Anatomy</a> | <a
-href="config.html">Postfix Configuration</a> | <a href="faq.html">Postfix
-FAQ</a>
-
-<h2>Table of contents</h2>
-
-<ul>
-
-<li><a href="motivation.html">Introduction</a>. How the Postfix
-mail system came into being, and what it attempts to achieve.
-
-<p>
-
-<li><a href="goals.html">Goals and features</a>. A summary of the
-specific problems that Postfix tries to solve.
-
-<p>
-
-<li><a href="architecture.html">Global architecture</a>. The global
-architecture of the Postfix mail system.
-
-<p>
-
-<li><a href="queuing.html">Queue management</a>. The Postfix queue
-organization, and the strategies that it uses for delivery.
-
-<p>
-
-<li><a href="security.html">Security</a>. Postfix was designed to
-just receive and deliver mail, without opening holes for intruders.
-
-</ul>
-
-<hr>
-
-<a href="index.html">Up one level</a> | Postfix Overview | <a
-href="anatomy.html">Postfix Anatomy</a> | <a
-href="config.html">Postfix Configuration</a> | <a href="faq.html">Postfix
-FAQ</a>
-
-</body>
-
-</html>
index 1afe00722112d2f7697b322d4c1d7795bac03048..bf92b71f82e4890b83837bbc5f7ae3048736931a 100644 (file)
@@ -48,17 +48,17 @@ PICKUP(8)                                               PICKUP(8)
        command after a configuration change.
 
 <b>Miscellaneous</b>
+       <b>always</b><i>_</i><b>bcc</b>
+              Address to send a copy of each message that  enters
+              the system.
+
        <b>mail</b><i>_</i><b>owner</b>
-              The process privileges used  while  not  opening  a
+              The  process  privileges  used  while not opening a
               <b>maildrop</b> file.
 
        <b>queue</b><i>_</i><b>directory</b>
               Top-level directory of the Postfix queue.
 
-<b>SEE</b> <b>ALSO</b>
-       <a href="cleanup.8.html">cleanup(8)</a> message canonicalization
-       <a href="master.8.html">master(8)</a> process manager
-       syslogd(8) system logging
 
 
 
@@ -71,8 +71,13 @@ PICKUP(8)                                               PICKUP(8)
 PICKUP(8)                                               PICKUP(8)
 
 
+<b>SEE</b> <b>ALSO</b>
+       <a href="cleanup.8.html">cleanup(8)</a> message canonicalization
+       <a href="master.8.html">master(8)</a> process manager
+       syslogd(8) system logging
+
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
@@ -117,11 +122,6 @@ PICKUP(8)                                               PICKUP(8)
 
 
 
-
-
-
-
-
 
 
 
index c5eb2c0ad933d363e405fd9eb58a18b16a2deb3f..2e9f14f621beeb74daa8a61124fb13cbf5d0e6c9 100644 (file)
@@ -30,7 +30,7 @@ PIPE(8)                                                   PIPE(8)
        file at the end of a service definition.  The syntax is as
        follows:
 
-       <b>flags=F</b>&gt; (optional)
+       <b>flags=FR</b>&gt; (optional)
               Optional message processing flags.  By  default,  a
               message is copied unchanged.
 
@@ -40,25 +40,25 @@ PIPE(8)                                                   PIPE(8)
                      <b>F</b> flag also  causes  an  empty  line  to  be
                      appended to the message.
 
-              &gt;      Prepend  &gt;  to  lines starting with "<b>From</b> ".
-                     This expected by, for  example,  <b>UUCP</b>  soft-
+              <b>R</b>      Prepend  a  <b>Return-Path:</b> message header with
+                     the envelope sender address.
+
+              &gt;      Prepend &gt; to lines starting  with  "<b>From</b>  ".
+                     This is expected by, for example, <b>UUCP</b> soft-
                      ware.
 
        <b>user</b>=<i>username</i> (required)
+
+       <b>user</b>=<i>username</i>:<i>groupname</i>
               The external command is executed with the rights of
-              the specified <i>username</i>.  The  software  refuses  to
-              execute  commands with root privileges, or with the
-              privileges of the mail system owner.
+              the  specified  <i>username</i>.   The software refuses to
+              execute commands with root privileges, or with  the
+              privileges  of  the mail system owner. If <i>groupname</i>
+              is specified, the corresponding group  ID  is  used
+              instead of the group ID of of <i>username</i>.
 
        <b>argv</b>=<i>command</i>... (required)
-              The command to be executed. This must be  specified
-              as the last command attribute.  The command is exe-
-              cuted  directly,  i.e.  without  interpretation  of
-              shell  meta  characters  by  a shell command inter-
-              preter.
-
-              In  the  command  argument  vector,  the  following
-              macros    are    recognized   and   replaced   with
+              The  command to be executed. This must be specified
 
 
 
@@ -71,24 +71,31 @@ PIPE(8)                                                   PIPE(8)
 PIPE(8)                                                   PIPE(8)
 
 
-              corresponding information from  the  Postfix  queue
-              manager delivery request:
+              as the last command attribute.  The command is exe-
+              cuted  directly,  i.e.  without  interpretation  of
+              shell meta characters by  a  shell  command  inter-
+              preter.
+
+              In  the  command  argument  vector,  the  following
+              macros are recognized and replaced with correspond-
+              ing  information  from  the  Postfix  queue manager
+              delivery request:
 
               <b>${extension</b>}
-                     This  macro expands to the extension part of
-                     a recipient address.  For example,  with  an
+                     This macro expands to the extension part  of
+                     a  recipient  address.  For example, with an
                      address  <i>user+foo@domain</i>  the  extension  is
-                     <i>foo</i>.  A command-line argument that  contains
-                     <b>${extension</b>}  expands  into as many command-
+                     <i>foo</i>.   A command-line argument that contains
+                     <b>${extension</b>} expands into as  many  command-
                      line arguments as there are recipients.
 
               <b>${mailbox</b>}
-                     This macro expands  to  the  complete  local
-                     part  of  a recipient address.  For example,
-                     with an address <i>user+foo@domain</i> the  mailbox
-                     is  <i>user+foo</i>.   A command-line argument that
-                     contains <b>${mailbox</b>}  expands  into  as  many
-                     command-line  arguments as there are recipi-
+                     This  macro  expands  to  the complete local
+                     part of a recipient address.   For  example,
+                     with  an address <i>user+foo@domain</i> the mailbox
+                     is <i>user+foo</i>.  A command-line  argument  that
+                     contains  <b>${mailbox</b>}  expands  into  as many
+                     command-line arguments as there are  recipi-
                      ents.
 
               <b>${nexthop</b>}
@@ -96,35 +103,28 @@ PIPE(8)                                                   PIPE(8)
 
               <b>${recipient</b>}
                      This macro expands to the complete recipient
-                     address.  A command-line argument that  con-
+                     address.   A command-line argument that con-
                      tains <b>${recipient</b>} expands into as many com-
                      mand-line arguments as there are recipients.
 
               <b>${sender</b>}
-                     This  macro  expands  to the envelope sender
+                     This macro expands to  the  envelope  sender
                      address.
 
               <b>${user</b>}
                      This macro expands to the username part of a
-                     recipient  address.   For  example,  with an
+                     recipient address.   For  example,  with  an
                      address <i>user+foo@domain</i> the username part is
                      <i>user</i>.  A command-line argument that contains
-                     <b>${user</b>} expands into  as  many  command-line
+                     <b>${user</b>}  expands  into  as many command-line
                      arguments as there are recipients.
 
-       In  addition  to  the  form  ${<i>name</i>},  the forms $<i>name</i> and
-       $(<i>name</i>) are also recognized.  Specify <b>$$</b> where a single  <b>$</b>
+       In addition to the  form  ${<i>name</i>},  the  forms  $<i>name</i>  and
+       $(<i>name</i>)  are also recognized.  Specify <b>$$</b> where a single <b>$</b>
        is wanted.
 
 <b>DIAGNOSTICS</b>
-       Command  exit status codes are expected to follow the con-
-       ventions defined in &lt;<b>sysexits.h</b>&gt;.
-
-       Problems and transactions are logged to <b>syslogd</b>(8).   Cor-
-       rupted  message files are marked so that the queue manager
-       can move them to the <b>corrupt</b> queue for further inspection.
-
-
+       Command exit status  codes  are  expected  to  follow  the
 
 
 
@@ -137,46 +137,52 @@ PIPE(8)                                                   PIPE(8)
 PIPE(8)                                                   PIPE(8)
 
 
+       conventions defined in &lt;<b>sysexits.h</b>&gt;.
+
+       Problems  and transactions are logged to <b>syslogd</b>(8).  Cor-
+       rupted message files are marked so that the queue  manager
+       can move them to the <b>corrupt</b> queue for further inspection.
+
 <b>SECURITY</b>
-       This  program  needs  a  dual personality 1) to access the
-       private Postfix queue and IPC mechanisms, and 2)  to  exe-
+       This program needs a dual personality  1)  to  access  the
+       private  Postfix  queue and IPC mechanisms, and 2) to exe-
        cute external commands as the specified user. It is there-
        fore security sensitive.
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The following <b>main.cf</b> parameters are  especially  relevant
-       to  this  program. See the Postfix <b>main.cf</b> file for syntax
-       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
+       The  following  <b>main.cf</b> parameters are especially relevant
+       to this program. See the Postfix <b>main.cf</b> file  for  syntax
+       details  and  for  default  values. Use the <b>postfix</b> <b>reload</b>
        command after a configuration change.
 
 <b>Miscellaneous</b>
        <b>mail</b><i>_</i><b>owner</b>
-              The  process  privileges  used while not running an
+              The process privileges used while  not  running  an
               external command.
 
 <b>Resource</b> <b>controls</b>
-       In the text below, <i>transport</i> is the first field in a  <b>mas-</b>
+       In  the text below, <i>transport</i> is the first field in a <b>mas-</b>
        <b>ter.cf</b> entry.
 
        <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
               Limit the number of parallel deliveries to the same
-              destination, for delivery via the named  <i>transport</i>.
-              The  default limit is taken from the <b>default</b><i>_</i><b>desti-</b>
-              <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.  The  limit  is
+              destination,  for delivery via the named <i>transport</i>.
+              The default limit is taken from the  <b>default</b><i>_</i><b>desti-</b>
+              <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>  parameter.   The limit is
               enforced by the Postfix queue manager.
 
        <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  the  number of recipients per message deliv-
-              ery, for delivery  via  the  named  <i>transport</i>.  The
-              default  limit  is  taken from the <b>default</b><i>_</i><b>destina-</b>
-              <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>  parameter.   The   limit   is
+              Limit the number of recipients per  message  deliv-
+              ery,  for  delivery  via  the  named <i>transport</i>. The
+              default limit is taken  from  the  <b>default</b><i>_</i><b>destina-</b>
+              <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>   parameter.    The  limit  is
               enforced by the Postfix queue manager.
 
        <i>transport_</i><b>time</b><i>_</i><b>limit</b>
-              Limit  the  time  for delivery to external command,
-              for delivery via the named <b>transport</b>.  The  default
-              limit  is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
-              ter.  The limit is enforced by  the  Postfix  queue
+              Limit the time for delivery  to  external  command,
+              for  delivery  via the named <b>transport</b>. The default
+              limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>  parame-
+              ter.   The  limit  is enforced by the Postfix queue
               manager.
 
 <b>SEE</b> <b>ALSO</b>
@@ -185,12 +191,6 @@ PIPE(8)                                                   PIPE(8)
        <a href="qmgr.8.html">qmgr(8)</a> queue manager
        syslogd(8) system logging
 
-<b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
-       software.
-
-<b>AUTHOR(S)</b>
-       Wietse Venema
 
 
 
@@ -203,6 +203,12 @@ PIPE(8)                                                   PIPE(8)
 PIPE(8)                                                   PIPE(8)
 
 
+<b>LICENSE</b>
+       The Secure Mailer license must be  distributed  with  this
+       software.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
        IBM T.J. Watson Research
        P.O. Box 704
        Yorktown Heights, NY 10598, USA
@@ -247,12 +253,6 @@ PIPE(8)                                                   PIPE(8)
 
 
 
-
-
-
-
-
-
 
 
 
index 29cfc8db03d654ca31550240c44ad228f9ed8b36..84f33515b6975987ec0a7e06ab360c0a73b7b133 100644 (file)
@@ -9,17 +9,20 @@ POSTCONF(1)                                           POSTCONF(1)
        postconf - Postfix configuration utility
 
 <b>SYNOPSIS</b>
-       <b>postconf</b> [<b>-d</b>] [<b>-n</b>] [<b>-v</b>] [<i>parameter</i> <i>...</i>]
+       <b>postconf</b> [<b>-d</b>] [<b>-h</b>] [<b>-n</b>] [<b>-v</b>] [<i>parameter</i> <i>...</i>]
 
 <b>DESCRIPTION</b>
        The  <b>postconf</b> command prints the actual value of <i>parameter</i>
-       (all known parameters by default).
+       (all known parameters by default), one parameter per line.
 
        Options:
 
-       <b>-d</b>     Print default parameter settings instead of  actual
+       <b>-d</b>     Print  default parameter settings instead of actual
               settings.
 
+       <b>-h</b>     Show parameter values only, not the <i>name</i> <i>=</i> informa-
+              tion that normally precedes the value.
+
        <b>-n</b>     Print non-default parameter settings only.
 
        <b>-v</b>     Enable  verbose mode for debugging purposes. Multi-
@@ -55,9 +58,6 @@ POSTCONF(1)                                           POSTCONF(1)
 
 
 
-
-
-
 
 
 
index 38855b4a914d005f28a3c2d4fc9c4f2abae87fa4..a994ce37b679807e9ed8d70397700a3aafbaeedc 100644 (file)
@@ -21,7 +21,7 @@ POSTDROP(1)                                           POSTDROP(1)
 
        The <b>postdrop</b> command is automatically invoked by the <a href="sendmail.1.html"><b>send-</b>
        <b>mail</b>(1)</a>  mail posting agent when the <b>maildrop</b> queue direc-
-       tory is not writable.
+       tory is not world-writable.
 
        Options:
 
diff --git a/postfix/html/postsuper.1.html b/postfix/html/postsuper.1.html
new file mode 100644 (file)
index 0000000..feddac5
--- /dev/null
@@ -0,0 +1,134 @@
+<html> <head> </head> <body> <pre>
+
+
+
+POSTSUPER(1)                                         POSTSUPER(1)
+
+
+<b>NAME</b>
+       postsuper - Postfix super intendent
+
+<b>SYNOPSIS</b>
+       <b>postsuper</b> [<b>-p</b>] [<b>-s</b>] [<b>-v</b>] [<i>directory</i> <i>...</i>]
+
+<b>DESCRIPTION</b>
+       The  <b>postsuper</b>  command does small maintenance jobs on the
+       named Postfix queue directories (default: all).  Directory
+       names  are  relative to the Postfix top-level queue direc-
+       tory.
+
+       By default, <b>postsuper</b> performs  the  operations  requested
+       with the <b>-s</b> and <b>-p</b> command-line options.  <b>postsuper</b> always
+       tries to remove objects that are neither files nor  direc-
+       tories.   Use  of this command is restricted to the super-
+       user.
+
+       Options:
+
+       <b>-s</b>     Structure check.  Move queue files that are in  the
+              wrong place in the file system hierarchy and remove
+              subdirectories that  are  no  longer  needed.  File
+              rearrangements  are necessary after a change in the
+              <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> and/or <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> configura-
+              tion  parameters.  It  is highly recommended to run
+              this check once before Postfix startup.
+
+       <b>-p</b>     Purge stale files (files that are left  over  after
+              system or software crashes).
+
+       <b>-v</b>     Enable  verbose mode for debugging purposes. Multi-
+              ple <b>-v</b> options make the software increasingly  ver-
+              bose.
+
+<b>DIAGNOSTICS</b>
+       Problems  are reported to the standard error stream and to
+       <b>syslogd</b>.
+
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+       See the Postfix <b>main.cf</b> file for syntax  details  and  for
+       default values.
+
+       <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b>
+              Number of subdirectory levels for hashed queues.
+
+       <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b>
+              The  names of queues that are organized into multi-
+              ple levels of subdirectories.
+
+<b>LICENSE</b>
+       The Secure Mailer license must be  distributed  with  this
+       software.
+
+
+
+
+                                                                1
+
+
+
+
+
+POSTSUPER(1)                                         POSTSUPER(1)
+
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
+       IBM T.J. Watson Research
+       P.O. Box 704
+       Yorktown Heights, NY 10598, USA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                2
+
+
+</pre> </body> </html>
index d9f0bac43796c28025757608b3846f4f915673a7..3769b015e3cb38abcaa882f6542472c06ea88995 100644 (file)
@@ -98,13 +98,11 @@ QMGR(8)                                                   QMGR(8)
               by slowly adjusting the number of parallel deliver-
               ies to the same destination.
 
-       <b>round</b> <b>robin</b> and <b>random</b> <b>walk</b>
+       <b>round</b> <b>robin</b>
               The queue manager sorts delivery requests by desti-
               nation.   Round-robin selection prevents one desti-
               nation from dominating deliveries to other destina-
-              tions.   Random  walk prevents one problematic mes-
-              sage from blocking deliveries of other mail to  the
-              same destination.
+              tions.
 
        <b>exponential</b> <b>backoff</b>
               Mail  that  cannot  be  delivered  upon  the  first
@@ -124,7 +122,9 @@ QMGR(8)                                                   QMGR(8)
        actions  (the message is followed by the symbolic constant
        used internally by the software):
 
-
+       <b>D</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>DEFERRED)</b>
+              Start a deferred queue scan.  If a  deferred  queue
+              scan  is  already  in  progress,  that scan will be
 
 
 
@@ -137,9 +137,6 @@ QMGR(8)                                                   QMGR(8)
 QMGR(8)                                                   QMGR(8)
 
 
-       <b>D</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>DEFERRED)</b>
-              Start a deferred queue scan.  If a  deferred  queue
-              scan  is  already  in  progress,  that scan will be
               restarted as soon as it finishes.
 
        <b>I</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>INCOMING)</b>
@@ -191,6 +188,9 @@ QMGR(8)                                                   QMGR(8)
 <b>BUGS</b>
        A  single  queue  manager  process has to compete for disk
        access with multiple front-end processes such as <b>smtpd</b>.  A
+       sudden  burst  of  inbound mail can negatively impact out-
+       bound delivery rates.
+
 
 
 
@@ -203,9 +203,6 @@ QMGR(8)                                                   QMGR(8)
 QMGR(8)                                                   QMGR(8)
 
 
-       sudden  burst  of  inbound mail can negatively impact out-
-       bound delivery rates.
-
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
        The following <b>main.cf</b> parameters are  especially  relevant
        to  this  program. See the Postfix <b>main.cf</b> file for syntax
@@ -256,7 +253,10 @@ QMGR(8)                                                   QMGR(8)
               ken delivery transport.
 
 <b>Concurrency</b> <b>controls</b>
-       In the text below, <i>transport</i>  is  the  first  field  in  a
+       In the text below, <i>transport</i> is the first field in a  <b>mas-</b>
+       <b>ter.cf</b> entry.
+
+
 
 
 
@@ -269,8 +269,6 @@ QMGR(8)                                                   QMGR(8)
 QMGR(8)                                                   QMGR(8)
 
 
-       <b>master.cf</b> entry.
-
        <b>initial</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b>
               Initial  per-destination concurrency level for par-
               allel delivery to the same destination.
@@ -326,6 +324,8 @@ QMGR(8)                                                   QMGR(8)
 
 
 
+
+
                                                                 5
 
 
index fe12f6165abcf9d4ffa2495633c561b7f746a0a0..13652fb2c2acf86ab2bf8b75f4f6f7db0287bba6 100644 (file)
@@ -13,7 +13,7 @@ Postfix Overview - Queue Management</h1>
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | <a href="architecture.html">Global architecture</a>
 | Queue Management | <a href="security.html">Security</a>
@@ -64,17 +64,15 @@ start</i> algorithm
 <h2>Fairness</h2>
 
 Apart from the <i>thundering herd</i> controls, the Postfix delivery
-strategy is based on <i>round-robin</i> selection and <i>random
-walks</i>.  The queue manager sorts message recipients in the active
-queue by destination, makes round-robin walks <i>along</i> all
-destination queues, and makes random walks <i>within</i> each
-destination queue.
+strategy is based on <i>round-robin</i> selection.  The queue
+manager sorts message recipients in the active queue by destination,
+and makes round-robin walks <i>along</i> all destination queues.
 
 <p>
 
 On the average, Postfix will do simultaneous deliveries to the same
 domain only when there is not enough work to keep all outbound SMTP
-channels busy. So, when AOL goes off-line and comes back, it will
+channels busy. So, when AOL goes off-line and comes back, it should
 not stop the system from delivering to other sites.
 
 <p>
@@ -108,7 +106,7 @@ mail backlog.
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | <a href="architecture.html">Global architecture</a>
 | Queue Management | <a href="security.html">Security</a>
index da7d46f0cd22e423e61e7a16cfaca6cf5aa8b82c..576c0656029f798be06c6855b2e4b8c9504da918 100644 (file)
@@ -14,7 +14,7 @@
 
 <hr>
 
-<a href="config.html">Up one level</a> |
+<a href="index.html">Up one level</a> |
 <a href="basic.html">Basic Configuration</a> | <a href="uce.html">UCE
 Controls</a> | Rate Controls | <a href="resource.html">Resource
 Controls</a> | <a href="rewrite.html">Address Manipulation</a>
@@ -395,7 +395,7 @@ That's of course no excuse.  I'm still looking for a good solution.
 
 <hr>
 
-<a href="config.html">Up one level</a> |
+<a href="index.html">Up one level</a> |
 <a href="basic.html">Basic Configuration</a> | <a href="uce.html">UCE
 Controls</a> | Rate Controls | <a href="resource.html">Resource
 Controls</a> | <a href="rewrite.html">Address Manipulation</a>
index 89dafba8121f5d8f549ade976e211509729f86d2..5168e643448df672601372d656acf806cc036db8 100644 (file)
@@ -13,7 +13,7 @@ Anatomy - Receiving Mail</h1>
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | Receiving Mail | <a
+<a href="index.html">Up one level</a> | Receiving Mail | <a
 href="delivering.html">Delivering Mail</a> | <a
 href="backstage.html">Behind the Scenes</a> | <a
 href="commands.html">Command-line Utilities</a>
@@ -107,7 +107,7 @@ href="rewrite.html">table lookup</a>.
 
 <hr>
 
-<a href="anatomy.html">Up one level</a> | Receiving Mail | <a
+<a href="index.html">Up one level</a> | Receiving Mail | <a
 href="delivering.html">Delivering Mail</a> | <a
 href="backstage.html">Behind the Scenes</a> | <a
 href="commands.html">Command-line Utilities</a>
index 386432a9199722fdb3e6c11f345ca96e7eb60a6a..cabadc1503aa6fa56f91af505d35368ac3f24543 100644 (file)
@@ -12,7 +12,7 @@
 
 <hr>
 
-<a href="config.html">Up one level</a> | <a href="basic.html">Basic
+<a href="index.html">Up one level</a> | <a href="basic.html">Basic
 Configuration</a> | <a href="uce.html">UCE Controls</a> | <a
 href="rate.html">Rate Controls</a> | Resource Controls | <a
 href="rewrite.html">Address Manipulation</a>
@@ -135,7 +135,7 @@ href="rate.html#backoff">delivery rate control</a> documentation.
 
 <dd> An upper limit on the number of messages in the <b>active</b>
 queue.  For an introduction to the Postfix queue organization see
-the <a href="overview.html">Postfix overview</a> documentation.
+the <a href="queuing.html">Postfix overview</a> documentation.
 
 <p>
 
@@ -267,7 +267,7 @@ an apparently defunct Postfix delivery service.
 
 <hr>
 
-<a href="config.html">Up one level</a> | <a href="basic.html">Basic
+<a href="index.html">Up one level</a> | <a href="basic.html">Basic
 Configuration</a> | <a href="uce.html">UCE Controls</a> | <a
 href="rate.html">Rate Controls</a> | Resource Controls | <a
 href="rewrite.html">Address Manipulation</a>
index 4838075760b9cffe2507d5ce59fe6d26279cadb3..4673d04093167bb064906b3597a6f9a26467ee20 100644 (file)
@@ -12,7 +12,7 @@
 
 <hr>
 
-<a href="config.html">Up one level</a> |
+<a href="index.html">Up one level</a> |
 <a href="basic.html"> Basic Configuration</a> | <a href="uce.html">UCE
 Controls</a> | <a href="rate.html"> Rate Controls</a> | <a
 href="resource.html"> Resource Controls</a> | Address Manipulation
@@ -73,6 +73,14 @@ Local delivery:
 
 <li> <a href="#aliases"> Alias database</a>
 
+<p>
+
+<li> <a href="#forward"> Per-user .forward files</a>
+
+<p>
+
+<li> <a href="#luser_relay"> Non-existent users</a>
+
 </ul>
 
 <a name="standard"> <h2> Rewrite addresses to standard form</h2>
@@ -392,9 +400,68 @@ are performed with the rights of the alias database owner.  A
 default userid, <b>default_privs</b>, is used for deliveries to
 commands/files in <i>root</i>-owned aliases.
 
+<a name="forward"> <h2> Per-user .forward files</h2>
+
+Users can control their own mail delivery by specifying destinations
+in a file called <b>.forward</b> in their home directories. The
+syntax of these files is the same as with system aliases, except
+that the lookup key and colon are not present.
+
+<a name="luser_relay"> <h2> Non-existent users</h2>
+
+When the local delivery agent finds that a message recipient does
+not exist, the message is normally bounced to the sender ("user
+unknown").  Sometimes it is desirable to forward mail for non-existing
+recipients to another machine.  For this purpose you can specify
+an alternative destination with the <b>luser_relay</b> configuration
+parameter.
+
+<p>
+
+Alternatively, mail for non-existent recipients can be delegated
+to an entirely different message transport, as specified with the
+<b>fallback_transport</b> configuration parameter. For details,
+see the <a href="local.8.html"> local</a> delivery agent.
+
+<p>
+
+<b>luser_relay</b> can specify any number of destinations that are
+valid in an alias file.  In fact, the same restrictions for command
+and file destinations apply as for true aliases.
+
+<p>
+
+In addition, some <b>luser_relay</b> destinations can receive
+special treatment:
+
+<p>
+
+<dl>
+
+<dt><b>luser_relay = </b><i>@some.where.else</i>
+
+<dd>The entire original recipient localpart is prepended. For
+example, mail for <i>unknown+foo</i> is sent to
+<i>unknown+foo@some.where.else</i>.
+
+<p>
+
+<dt><b>luser_relay = </b><i>someone@some.where.else</i>
+<dt><b>luser_relay = </b><i>someone</i>
+
+<dd>If no <b>recipient_delimiter</b> has been specified, mail is
+sent to the <b>luser_relay</b> address. If the <b>recipient_delimiter</b>
+has been specified, the entire original recipient localpart is
+appended as an address extension to the <b>luser_relay</b> address.
+For example, with <b>recipient_delimiter = +</b>, mail for
+<i>unknown+foo</i> is sent to <i>someone+unknown+foo@some.where.else</i>
+and <i>someone+unknown+foo</i>, respectively.
+
+</dl>
+
 <hr>
 
-<a href="config.html">Up one level</a> |
+<a href="index.html">Up one level</a> |
 <a href="basic.html"> Basic Configuration</a> | <a href="uce.html">UCE
 Controls</a> | <a href="rate.html"> Rate Controls</a> | <a
 href="resource.html"> Resource Controls</a> | Address Manipulation
index 63530cecbb20e0ae4afebfeca461b9077a051524..3dfcc7962c1feefa7a0514f869943724d8f11ec9 100644 (file)
@@ -13,7 +13,7 @@ Overview - Security</h1>
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | <a href="architecture.html">Global architecture</a>
 | <a href="queuing.html">Queue Management</a> | Security
@@ -170,7 +170,7 @@ to prevent runaway conditions that only make problems worse.
 
 <hr>
 
-<a href="overview.html">Up one level</a> | <a
+<a href="index.html">Up one level</a> | <a
 href="motivation.html">Introduction</a> | <a href="goals.html">Goals
 and features</a> | <a href="architecture.html">Global architecture</a>
 | <a href="queuing.html">Queue Management</a> | Security
index 143cd03c5d09bf389fd5aef3bf6fbf07033e4c38..421cb3141a090035e3d433f5426fedd910ad9ce9 100644 (file)
@@ -25,10 +25,10 @@ SENDMAIL(1)                                           SENDMAIL(1)
 
        By default, <b>sendmail</b> reads a message from  standard  input
        and  arranges for delivery.  <b>sendmail</b> attempts to create a
-       queue file in the <b>maildrop</b> directory. If the  process  has
-       no  write  permission,  the  message  is piped through the
-       <a href="postdrop.1.html"><b>postdrop</b>(1)</a> command, which is  expected  to  execute  with
-       suitable privileges.
+       queue file in the <b>maildrop</b> directory. If that directory is
+       not world-writable, the message is piped through the <b>post-</b>
+       <b>drop</b>(1) command, which is expected to execute  with  suit-
+       able privileges.
 
        Specific  command  aliases  are  provided for other common
        modes of operation:
@@ -165,32 +165,32 @@ SENDMAIL(1)                                           SENDMAIL(1)
               Set option <i>x</i> to <i>value</i>. Use the equivalent  configu-
               ration parameter in <b>main.cf</b> instead.
 
-       <b>-q</b>     Flush  the mail queue. This is implemented by kick-
+       <b>-r</b> <i>sender</i>
+              Set  the  envelope  sender  address.  This  is  the
+              address where delivery problems are sent to, unless
+              the  message contains an <b>Errors-To:</b> message header.
+
+       <b>-q</b>     Flush the mail queue. This is implemented by  kick-
               ing the <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon.
 
        <b>-q</b><i>interval</i> (ignored)
-              The  interval   between   queue   runs.   Use   the
+              The   interval   between   queue   runs.   Use  the
               <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead.
 
-       <b>-t</b>     Extract   recipients  from  message  headers.  This
-              requires that no recipients  be  specified  on  the
+       <b>-t</b>     Extract  recipients  from  message  headers.   This
+              requires  that  no  recipients  be specified on the
               command line.
 
        <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
-              tiple <b>-v</b> options  make  the  software  increasingly
+              tiple  <b>-v</b>  options  make  the software increasingly
               verbose.
 
 <b>SECURITY</b>
-       By  design,  this  program  is not set-user (or group) id.
-       However, it must  handle  data  from  untrusted  users  or
-       untrusted  machines.   Thus, the usual precautions need to
+       By design, this program is not  set-user  (or  group)  id.
+       However,  it  must  handle  data  from  untrusted users or
+       untrusted machines.  Thus, the usual precautions  need  to
        be taken against malicious inputs.
 
-<b>DIAGNOSTICS</b>
-       Problems are logged to  <b>syslogd</b>(8)  and  to  the  standard
-       error stream.
-
-
 
 
 
@@ -203,6 +203,10 @@ SENDMAIL(1)                                           SENDMAIL(1)
 SENDMAIL(1)                                           SENDMAIL(1)
 
 
+<b>DIAGNOSTICS</b>
+       Problems  are  logged  to  <b>syslogd</b>(8)  and to the standard
+       error stream.
+
 <b>ENVIRONMENT</b>
        <b>MAIL</b><i>_</i><b>CONFIG</b>
               Directory with Postfix configuration files.
@@ -212,7 +216,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
 
        <b>MAIL</b><i>_</i><b>DEBUG</b>
               Enable debugging with an external command, as spec-
-              ified  with  the   <b>debugger</b><i>_</i><b>command</b>   configuration
+              ified   with   the  <b>debugger</b><i>_</i><b>command</b>  configuration
               parameter.
 
 <b>FILES</b>
@@ -220,13 +224,13 @@ SENDMAIL(1)                                           SENDMAIL(1)
        /etc/postfix, configuration files
 
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       See  the  Postfix  <b>main.cf</b> file for syntax details and for
-       default values. Use the <b>postfix</b>  <b>reload</b>  command  after  a
+       See the Postfix <b>main.cf</b> file for syntax  details  and  for
+       default  values.  Use  the  <b>postfix</b> <b>reload</b> command after a
        configuration change.
 
        <b>alias</b><i>_</i><b>database</b>
-              Default   alias  database(s)  for  <b>newaliases</b>.  The
-              default value for  this  parameter  is  system-spe-
+              Default  alias  database(s)  for  <b>newaliases</b>.   The
+              default  value  for  this  parameter is system-spe-
               cific.
 
        <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b>
@@ -242,20 +246,16 @@ SENDMAIL(1)                                           SENDMAIL(1)
               initialized.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
-              Increment in verbose logging level  when  a  remote
+              Increment  in  verbose  logging level when a remote
               host  matches  a  pattern  in  the  <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
               parameter.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
-              List of domain or network patterns. When  a  remote
-              host  matches  a pattern, increase the verbose log-
-              ging  level  by  the  amount   specified   in   the
+              List  of  domain or network patterns. When a remote
+              host matches a pattern, increase the  verbose  log-
+              ging   level   by   the  amount  specified  in  the
               <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
 
-       <b>fork</b><i>_</i><b>attempts</b>
-              Number  of attempts to <b>fork</b>() a process before giv-
-              ing up.
-
 
 
 
@@ -269,32 +269,36 @@ SENDMAIL(1)                                           SENDMAIL(1)
 SENDMAIL(1)                                           SENDMAIL(1)
 
 
+       <b>fork</b><i>_</i><b>attempts</b>
+              Number of attempts to <b>fork</b>() a process before  giv-
+              ing up.
+
        <b>fork</b><i>_</i><b>delay</b>
-              Delay  in   seconds   between   successive   <b>fork</b>()
+              Delay   in   seconds   between   successive  <b>fork</b>()
               attempts.
 
        <b>hopcount</b><i>_</i><b>limit</b>
               Limit the number of <b>Received:</b> message headers.
 
        <b>mail</b><i>_</i><b>owner</b>
-              The  owner  of  the  mail queue and of most Postfix
+              The owner of the mail queue  and  of  most  Postfix
               processes.
 
        <b>command</b><i>_</i><b>directory</b>
-              Directory with Postfix support  commands  (default:
+              Directory  with  Postfix support commands (default:
               <b>$program</b><i>_</i><b>directory</b>).
 
        <b>daemon</b><i>_</i><b>directory</b>
-              Directory  with  Postfix  daemon programs (default:
+              Directory with Postfix  daemon  programs  (default:
               <b>$program</b><i>_</i><b>directory</b>).
 
        <b>queue</b><i>_</i><b>directory</b>
-              Top-level directory of the Postfix queue.  This  is
+              Top-level  directory  of the Postfix queue. This is
               also the root directory of Postfix daemons that run
               chrooted.
 
        <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
-              The time between successive scans of  the  deferred
+              The  time  between successive scans of the deferred
               queue.
 
 <b>SEE</b> <b>ALSO</b>
@@ -309,7 +313,7 @@ SENDMAIL(1)                                           SENDMAIL(1)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
@@ -322,10 +326,6 @@ SENDMAIL(1)                                           SENDMAIL(1)
 
 
 
-
-
-
-
                                                                 5
 
 
index d6cef08c73d182af4e5f42cf060e2fcaf3571fd5..036a46c70b7938b63b56f831113e869cfd7a8cd2 100644 (file)
@@ -84,61 +84,79 @@ SMTP(8)                                                   SMTP(8)
               ging  level  by  the  amount   specified   in   the
               <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
 
+       <b>fallback</b><i>_</i><b>relay</b>
+              Hosts  to hand off mail to if a message destination
+              is not found or if a destination is unreachable.
+
+       <b>ignore</b><i>_</i><b>mx</b><i>_</i><b>lookup</b><i>_</i><b>error</b>
+              When a name server fails to respond to an MX query,
+              search for an A record instead of assuming that the
+              name server will recover.
+
        <b>inet</b><i>_</i><b>interfaces</b>
               The network interface addresses that this mail sys-
-              tem receives mail on. When any of  those  addresses
+              tem  receives  mail on. When any of those addresses
               appears in the list of mail exchangers for a remote
-              destination, the list is truncated  to  avoid  mail
+              destination,  the  list  is truncated to avoid mail
               delivery loops.
 
        <b>notify</b><i>_</i><b>classes</b>
-              When  this  parameter  includes the <b>protocol</b> class,
-              send mail to the  postmaster  with  transcripts  of
+              When this parameter includes  the  <b>protocol</b>  class,
+              send  mail  to  the  postmaster with transcripts of
               SMTP sessions with protocol errors.
 
+       <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
+              Skip servers that greet us with a 4xx status  code.
+
+       <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b>
+              Do  not  wait for the server response after sending
+              QUIT.
+
 <b>Resource</b> <b>controls</b>
        <b>smtp</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
               Limit the number of parallel deliveries to the same
-              destination.  The default limit is taken  from  the
+              destination.   The  default limit is taken from the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
 
        <b>smtp</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  the  number of recipients per message deliv-
-              ery.   The  default  limit  is   taken   from   the
+              Limit the number of recipients per  message  deliv-
+              ery.    The   default   limit  is  taken  from  the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
 
 <b>Timeout</b> <b>controls</b>
+
+
+
+
+                                                                2
+
+
+
+
+
+SMTP(8)                                                   SMTP(8)
+
+
        <b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
               Timeout in seconds for completing a TCP connection.
               When no connection can be made within the deadline,
-              the  SMTP client tries the next address on the mail
+              the SMTP client tries the next address on the  mail
               exchanger list.
 
        <b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
-              Timeout in seconds for receiving the SMTP  greeting
+              Timeout  in seconds for receiving the SMTP greeting
               banner.  When the server drops the connection with-
-              out sending a greeting banner, or when it sends  no
+              out  sending a greeting banner, or when it sends no
               greeting  banner  within  the  deadline,  the  SMTP
               client tries the next address on the mail exchanger
               list.
 
        <b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
-              Timeout  in  seconds  for sending the <b>HELO</b> command,
+              Timeout in seconds for sending  the  <b>HELO</b>  command,
               and for receiving the server response.
 
-
-
-                                                                2
-
-
-
-
-
-SMTP(8)                                                   SMTP(8)
-
-
        <b>smtp</b><i>_</i><b>mail</b><i>_</i><b>timeout</b>
-              Timeout in seconds for sending the <b>MAIL</b>  <b>FROM</b>  com-
+              Timeout  in  seconds for sending the <b>MAIL</b> <b>FROM</b> com-
               mand, and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>rcpt</b><i>_</i><b>timeout</b>
@@ -146,7 +164,7 @@ SMTP(8)                                                   SMTP(8)
               and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>init</b><i>_</i><b>timeout</b>
-              Timeout in seconds for sending  the  <b>DATA</b>  command,
+              Timeout  in  seconds  for sending the <b>DATA</b> command,
               and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
@@ -155,11 +173,11 @@ SMTP(8)                                                   SMTP(8)
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>done</b><i>_</i><b>timeout</b>
               Timeout in seconds for sending the "<b>.</b>" command, and
               for receiving the server response. When no response
-              is received, a warning is logged that the mail  may
+              is  received, a warning is logged that the mail may
               be delivered multiple times.
 
        <b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
-              Timeout  in  seconds  for sending the <b>QUIT</b> command,
+              Timeout in seconds for sending  the  <b>QUIT</b>  command,
               and for receiving the server response.
 
 <b>SEE</b> <b>ALSO</b>
@@ -169,9 +187,22 @@ SMTP(8)                                                   SMTP(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
+
+
+
+
+                                                                3
+
+
+
+
+
+SMTP(8)                                                   SMTP(8)
+
+
 <b>AUTHOR(S)</b>
        Wietse Venema
        IBM T.J. Watson Research
@@ -194,7 +225,42 @@ SMTP(8)                                                   SMTP(8)
 
 
 
-                                                                3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                4
 
 
 </pre> </body> </html>
index 497fd1c2091d9398d15c6b2e6b41f9af698b9078..1f3636dbaf3c5f291583e1c64957e19e8a47f5a3 100644 (file)
@@ -74,19 +74,23 @@ SMTPD(8)                                                 SMTPD(8)
        command after a configuration change.
 
 <b>Miscellaneous</b>
+       <b>always</b><i>_</i><b>bcc</b>
+              Address  to send a copy of each message that enters
+              the system.
+
        <b>command</b><i>_</i><b>directory</b>
               Location  of  Postfix  support  commands  (default:
               <b>$program</b><i>_</i><b>directory</b>).
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
-              Increment in verbose logging level  when  a  remote
+              Increment  in  verbose  logging level when a remote
               host  matches  a  pattern  in  the  <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
               parameter.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
-              List of domain or network patterns. When  a  remote
-              host  matches  a pattern, increase the verbose log-
-              ging  level  by  the  amount   specified   in   the
+              List  of  domain or network patterns. When a remote
+              host matches a pattern, increase the  verbose  log-
+              ging   level   by   the  amount  specified  in  the
               <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
 
        <b>hopcount</b><i>_</i><b>limit</b>
@@ -95,37 +99,33 @@ SMTPD(8)                                                 SMTPD(8)
        <b>notify</b><i>_</i><b>classes</b>
               List of error classes. Of special interest are:
 
-              <b>policy</b> When  a  client  violates any policy, mail a
+              <b>policy</b> When a client violates any  policy,  mail  a
                      transcript of the entire SMTP session to the
                      postmaster.
 
               <b>protocol</b>
-                     When  a client violates the SMTP protocol or
+                     When a client violates the SMTP protocol  or
                      issues  an  unimplemented  command,  mail  a
                      transcript of the entire SMTP session to the
                      postmaster.
 
        <b>smtpd</b><i>_</i><b>banner</b>
-              Text that follows the <b>220</b> status code in  the  SMTP
+              Text  that  follows the <b>220</b> status code in the SMTP
               greeting banner.
 
        <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Restrict  the  number  of  recipients that the SMTP
+              Restrict the number of  recipients  that  the  SMTP
               server accepts per message delivery.
 
        <b>smtpd</b><i>_</i><b>timeout</b>
-              Limit the time to send a  server  response  and  to
+              Limit  the  time  to  send a server response and to
               receive a client request.
 
 <b>Resource</b> <b>controls</b>
        <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
-              Limit  the  amount  of memory in bytes used for the
+              Limit the amount of memory in bytes  used  for  the
               handling of partial input lines.
 
-       <b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
-              Limit the total size in bytes of a message, includ-
-              ing on-disk storage for envelope information.
-
 
 
                                                                 2
@@ -137,9 +137,13 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+       <b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
+              Limit the total size in bytes of a message, includ-
+              ing on-disk storage for envelope information.
+
        <b>queue</b><i>_</i><b>minfree</b>
-              Minimal  amount of free space in bytes in the queue
-              file system for the SMTP server to accept any  mail
+              Minimal amount of free space in bytes in the  queue
+              file  system for the SMTP server to accept any mail
               at all.
 
 <b>Tarpitting</b>
@@ -149,11 +153,11 @@ SMTPD(8)                                                 SMTPD(8)
 
        <b>smtpd</b><i>_</i><b>soft</b><i>_</i><b>error</b><i>_</i><b>limit</b>
               When an SMTP client has made this number of errors,
-              wait  <i>error_count</i>  seconds before responding to any
+              wait <i>error_count</i> seconds before responding  to  any
               client request.
 
        <b>smtpd</b><i>_</i><b>hard</b><i>_</i><b>error</b><i>_</i><b>limit</b>
-              Disconnect after a client has made this  number  of
+              Disconnect  after  a client has made this number of
               errors.
 
 <b>UCE</b> <b>control</b> <b>restrictions</b>
@@ -162,19 +166,19 @@ SMTPD(8)                                                 SMTPD(8)
               tem.
 
        <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>required</b>
-              Require that clients introduce  themselves  at  the
+              Require  that  clients  introduce themselves at the
               beginning of an SMTP session.
 
        <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>restrictions</b>
-              Restrict  what client hostnames are allowed in <b>HELO</b>
+              Restrict what client hostnames are allowed in  <b>HELO</b>
               and <b>EHLO</b> commands.
 
        <b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>restrictions</b>
-              Restrict what sender addresses are allowed in  <b>MAIL</b>
+              Restrict  what sender addresses are allowed in <b>MAIL</b>
               <b>FROM</b> commands.
 
        <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b>
-              Restrict  what  recipient  addresses are allowed in
+              Restrict what recipient addresses  are  allowed  in
               <b>RCPT</b> <b>TO</b> commands.
 
        <b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b>
@@ -182,15 +186,11 @@ SMTPD(8)                                                 SMTPD(8)
               mands, and what clients may issue <b>ETRN</b> commands.
 
        <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b>
-              List  of  DNS domains that publish the addresses of
+              List of DNS domains that publish the  addresses  of
               blacklisted hosts.
 
        <b>relay</b><i>_</i><b>domains</b>
-              Restrict what domains or networks this mail  system
-              will relay mail from or to.
-
-<b>UCE</b> <b>control</b> <b>responses</b>
-
+              Restrict  what domains or networks this mail system
 
 
 
@@ -203,37 +203,40 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+              will relay mail from or to.
+
+<b>UCE</b> <b>control</b> <b>responses</b>
        <b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server  response  when  a client violates an access
+              Server response when a client  violates  an  access
               database restriction.
 
        <b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server  response  when  a   client   violates   the
+              Server   response   when   a  client  violates  the
               <b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction.
 
        <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server   response   when   a  client  violates  the
+              Server  response  when  a   client   violates   the
               <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction.
 
        <b>reject</b><i>_</i><b>code</b>
-              Response code when  the  client  matches  a  <b>reject</b>
+              Response  code  when  the  client  matches a <b>reject</b>
               restriction.
 
        <b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server  response  when a client attempts to violate
+              Server response when a client attempts  to  violate
               the mail relay policy.
 
        <b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server  response  when  a   client   violates   the
+              Server   response   when   a  client  violates  the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
 
        <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server  response  when  a client without address to
-              name mapping  violates  the  <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
+              Server response when a client  without  address  to
+              name  mapping  violates  the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
               restriction.
 
        <b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Server   response   when   a  client  violates  the
+              Server  response  when  a   client   violates   the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
 
 <b>SEE</b> <b>ALSO</b>
@@ -242,7 +245,7 @@ SMTPD(8)                                                 SMTPD(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -257,9 +260,6 @@ SMTPD(8)                                                 SMTPD(8)
 
 
 
-
-
-
                                                                 4
 
 
index b86c7f79faf8292445436fd32a500b84204cc173..86c81d8ed1c54f1909f0fe42b2d7cfcd27d9d42a 100644 (file)
@@ -13,7 +13,7 @@ Postfix Configuration - UCE Controls</h1>
 
 <hr>
 
-<a href="config.html">Up one level</a> | <a href="basic.html">Basic
+<a href="index.html">Up one level</a> | <a href="basic.html">Basic
 Configuration</a> | UCE Controls | <a href="rate.html">Rate
 Controls</a> | <a href="resource.html">Resource Controls</a> | <a
 href="rewrite.html">Address Manipulation </a>
@@ -275,6 +275,15 @@ response code to rejected requests (default:  <b>450</b>).
 
 <p>
 
+<a name="reject_non_fqdn_hostname">
+
+<dt> <b>reject_non_fqdn_hostname</b> <dd> Reject the request when
+the hostname in the client HELO (EHLO) command is not in fully-qualified
+domain form. The <b>non_fqdn_reject_code</b> specifies the
+response code to rejected requests (default:  <b>504</b>).
+
+<p>
+
 <a name="check_helo_access">
 
 <dt> <b>check_helo_access</b> <i>maptype</i>:<i>mapname</i>
@@ -375,12 +384,23 @@ request if the result is anything else.  The <b>access_map_reject_code
 
 <p>
 
+<a name="reject_non_fqdn_sender">
+
+<dt> <b>reject_non_fqdn_sender</b> <dd> Reject the request when
+the address in the client MAIL FROM command is not in fully-qualified
+domain form. The <b>non_fqdn_reject_code</b> specifies the
+response code to rejected requests (default:  <b>504</b>).
+
+<p>
+
 <dt> <b><a href="#permit_naked_ip_address">permit_naked_ip_address</a></b>
 
 <dt> <b><a href="#reject_invalid_hostname">reject_invalid_hostname</a></b>
 
 <dt> <b><a href="#reject_unknown_hostname">reject_unknown_hostname</a></b>
 
+<dt> <b><a href="#reject_non_fqdn_hostname">reject_non_fqdn_hostname</a></b>
+
 <dt> <b><a href="#check_helo_access">check_helo_access</a></b> <i>maptype</i>:<i>mapname</i>
 
 <dd> See HELO (EHLO) hostname restrictions.
@@ -486,8 +506,19 @@ for rejected requests (default: <b>550</b>).
 
 <p>
 
+<a name="reject_non_fqdn_recipient">
+
+<dt> <b>reject_non_fqdn_recipient</b> <dd> Reject the request when
+the address in the client RCPT TO command is not in fully-qualified
+domain form. The <b>non_fqdn_reject_code</b> specifies the
+response code to rejected requests (default:  <b>504</b>).
+
+<p>
+
 <dt> <b><a href="#reject_unknown_address">reject_unknown_address</a></b>
 
+<dt> <b><a href="#reject_non_fqdn_sender">reject_non_fqdn_sender</a></b>
+
 <dt> <b><a href="#check_sender_access">check_sender_access</a></b> <i>maptype</i>:<i>mapname</i>
 
 <dd> See sender address restrictions.
@@ -500,6 +531,8 @@ for rejected requests (default: <b>550</b>).
 
 <dt> <b><a href="#reject_unknown_hostname">reject_unknown_hostname</a></b>
 
+<dt> <b><a href="#reject_non_fqdn_hostname">reject_non_fqdn_hostname</a></b>
+
 <dt> <b><a href="#check_helo_access">check_helo_access</a></b> <i>maptype</i>:<i>mapname</i>
 
 <dd> See HELO (EHLO) hostname restrictions.
@@ -670,7 +703,7 @@ appear as part of a client name/address restriction list.
 
 <dt>Default:
 
-<dd><b>maps_rbl_domains = rbl.maps.vix.com</b>
+<dd><b>maps_rbl_domains = rbl.maps.vix.com, dul.maps.vix.com</b>
 
 <p>
 
@@ -727,7 +760,7 @@ tables listed in <b>$relay_domains.</b>
 
 <hr>
 
-<a href="config.html">Up one level</a> | <a href="basic.html">Basic
+<a href="index.html">Up one level</a> | <a href="basic.html">Basic
 Configuration</a> | UCE Controls | <a href="rate.html">Rate
 Controls</a> | <a href="resource.html">Resource Controls</a> | <a
 href="rewrite.html">Address Manipulation </a>
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 99c60e1ec7af9d0df9af357feb71c591203fa946..487b63d30852e39005fd2d0a923b066b534890cc 100644 (file)
@@ -1,10 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = alias.c command.c delivered.c dotforward.c file.c forward.c \
        include.c indirect.c local.c mailbox.c recipient.c resolve.c token.c \
-       deliver_attr.c feature.c maildir.c biff_notify.c
+       deliver_attr.c feature.c maildir.c biff_notify.c unknown.c
 OBJS   = alias.o command.o delivered.o dotforward.o file.o forward.o \
        include.o indirect.o local.o mailbox.o recipient.o resolve.o token.o \
-       deliver_attr.o feature.o maildir.o biff_notify.o
+       deliver_attr.o feature.o maildir.o biff_notify.o unknown.o
 HDRS   = local.h
 TESTSRC        =
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -277,8 +277,8 @@ mailbox.o: ../include/set_eugid.h
 mailbox.o: ../include/mail_copy.h
 mailbox.o: ../include/safe_open.h
 mailbox.o: ../include/deliver_flock.h
-mailbox.o: ../include/bounce.h
 mailbox.o: ../include/defer.h
+mailbox.o: ../include/bounce.h
 mailbox.o: ../include/sent.h
 mailbox.o: ../include/mypwd.h
 mailbox.o: ../include/been_here.h
@@ -318,7 +318,6 @@ recipient.o: ../include/dict.h
 recipient.o: ../include/vstream.h
 recipient.o: ../include/vbuf.h
 recipient.o: ../include/bounce.h
-recipient.o: ../include/defer.h
 recipient.o: ../include/mail_params.h
 recipient.o: ../include/split_addr.h
 recipient.o: local.h
@@ -356,3 +355,18 @@ token.o: ../include/resolve_clnt.h
 token.o: ../include/mail_params.h
 token.o: local.h
 token.o: ../include/been_here.h
+unknown.o: unknown.c
+unknown.o: ../include/sys_defs.h
+unknown.o: ../include/msg.h
+unknown.o: ../include/stringops.h
+unknown.o: ../include/mymalloc.h
+unknown.o: ../include/been_here.h
+unknown.o: ../include/mail_params.h
+unknown.o: ../include/bounce.h
+unknown.o: local.h
+unknown.o: ../include/htable.h
+unknown.o: ../include/vstream.h
+unknown.o: ../include/vbuf.h
+unknown.o: ../include/vstring.h
+unknown.o: ../include/tok822.h
+unknown.o: ../include/resolve_clnt.h
index 15654e6e879f9bb123690957509d8618e689dedd..90bfe4f9a86c323bcdad84543b2cf08d4e5db7f9 100644 (file)
@@ -136,7 +136,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
     state.level++;
     if (msg_verbose)
-       msg_info("%s[%d]: %s", myname, state.level, state.msg_attr.local);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * Do this only once.
index 2ef58fe535035dd2ad7e2f8373220056c80ede29..1502a46d2c3ad7136efe3bebe37ac4d392c2a578 100644 (file)
@@ -82,6 +82,13 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
     ARGV   *env;
     int     copy_flags;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
+    if (msg_verbose)
+       MSG_LOG_STATE(myname, state);
+
     /*
      * DUPLICATE ELIMINATION
      * 
@@ -114,7 +121,7 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command)
     /*
      * Deliver.
      */
-    copy_flags = MAIL_COPY_FROM;
+    copy_flags = MAIL_COPY_FROM | MAIL_COPY_RETURN_PATH;
     if ((state.msg_attr.features & FEATURE_NODELIVERED) == 0)
        copy_flags |= MAIL_COPY_DELIVERED;
 
index 5e4cffaec6bfbbc7df166d86835128b2122f9c1b..2c0f2c001144f3526480a8e3696b7d894e02bb67 100644 (file)
@@ -100,13 +100,14 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     int     forward_found = NO;
     int     lookup_status;
     int     addr_count;
+    char   *extension;
 
     /*
      * Make verbose logging easier to understand.
      */
     state.level++;
     if (msg_verbose)
-       msg_info("%s[%d]: %s", myname, state.level, state.msg_attr.local);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * DUPLICATE/LOOP ELIMINATION
@@ -169,8 +170,8 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     state.msg_attr.owner = state.msg_attr.recipient;
 
     /*
-     * Assume that usernames do not have file system meta characters. Open the
-     * .forward file as the user. Ignore files that aren't regular files,
+     * Assume that usernames do not have file system meta characters. Open
+     * the .forward file as the user. Ignore files that aren't regular files,
      * files that are owned by the wrong user, or files that have world write
      * permission enabled. We take no special precautions to deal with home
      * directories imported via NFS, because mailbox and .forward files
@@ -185,19 +186,20 @@ int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
 
     status = 0;
     path = vstring_alloc(100);
-    if (state.msg_attr.extension && strchr(state.msg_attr.extension, '/')) {
+    extension = state.msg_attr.extension;
+    if (extension && strchr(extension, '/')) {
        msg_warn("%s: address with illegal extension: %s",
                 state.msg_attr.queue_id, state.msg_attr.recipient);
-       state.msg_attr.extension = 0;
+       extension = 0;
     }
-    if (state.msg_attr.extension != 0) {
+    if (extension != 0) {
        vstring_sprintf(path, "%s/.forward%c%s", mypwd->pw_dir,
-                       var_rcpt_delim[0], state.msg_attr.extension);
+                       var_rcpt_delim[0], extension);
        if ((lookup_status = lstat_as(STR(path), &st,
                                      usr_attr.uid, usr_attr.gid)) < 0)
-           state.msg_attr.extension = 0;
+           extension = 0;
     }
-    if (state.msg_attr.extension == 0) {
+    if (extension == 0) {
        vstring_sprintf(path, "%s/.forward", mypwd->pw_dir);
        lookup_status = lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid);
     }
index d9ff9592b162991c077ad6e0af69b7cb45f9c6d5..3b8dcc4496d269c5847606e98ec6d0c994870ced 100644 (file)
@@ -79,6 +79,7 @@
 
 int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
 {
+    char   *myname = "deliver_file";
     struct stat st;
     int     fd;
     VSTREAM *dst;
@@ -86,6 +87,13 @@ int     deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     int     status;
     int     copy_flags;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
+    if (msg_verbose)
+       MSG_LOG_STATE(myname, state);
+
     /*
      * DUPLICATE ELIMINATION
      * 
index d9f0786bc17880e825a7eed7fd1cfcef2c713256..38a8d72ad042abe8f372c5b83dfadb9935d8e6ed 100644 (file)
@@ -88,7 +88,7 @@ int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
      */
     state.level++;
     if (msg_verbose)
-       msg_info("%s[%d]: %s", myname, state.level, path);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * DUPLICATE ELIMINATION
index 22dcccbe3fb69a3722ec46d8bdb95e28f44ca606..1daed8a357f0586000c208382cdda384a6fecc1a 100644 (file)
 /* MAILBOX DELIVERY
 /* .ad
 /* .fi
-/*     The per-user mailbox is either a file in the default UNIX mailbox
-/*     directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR)
-/*     or it is a file in the user's home directory with a name specified
-/*     via the \fBhome_mailbox\fR configuration parameter. Specify a path
-/*     name ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR
-/*     delivery.
+/*     The default per-user mailbox is a file in the UNIX mail spool
+/*     directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR);
+/*     the location can be specified with the \fBmail_spool_directory\fR
+/*     configuration parameter.
+/*
+/*     Alternatively, the per-user mailbox can be a file in the user's home
+/*     directory with a name specified via the \fBhome_mailbox\fR
+/*     configuration parameter. Specify a relative path name. Specify a name
+/*     ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR delivery.
+/*
 /*     Mailbox delivery can be delegated to an external command specified
-/*     with the \fBmailbox_command\fR configuration parameter.
+/*     with the \fBmailbox_command\fR configuration parameter. The command
+/*     executes with the privileges of the recipient user (exception: in
+/*     case of delivery as root, the command executes with the privileges
+/*     of \fBdefault_user\fR).
 /*
-/*     The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
+/*     Mailbox delivery can be delegated to alternative message transports
+/*     specified in the \fBmaster.cf\fR file.
+/*     The \fBmailbox_transport\fR configuration parameter specifies a
+/*     message transport that is to be used for all local recipients,
+/*     regardless of whether they are found in the UNIX passwd database.
+/*     The \fBfallback_transport\fR parameter specifies a message transport
+/*     for recipients that are not found in the UNIX passwd database.
+/*
+/*     In the case of UNIX-style mailbox delivery,
+/*     the \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
 /*     envelope header to each message, prepends a \fBDelivered-To:\fR header
-/*     with the envelope recipient address, prepends a \fB>\fR character to
-/*     lines beginning with "\fBFrom \fR", and appends an empty line.
-/*     The envelope sender address is available in the \fBReturn-Path:\fR
-/*     header.
+/*     with the envelope recipient address, prepends a \fBReturn-Path:\fR
+/*     header with the envelope sender address, prepends a \fB>\fR character
+/*     to lines beginning with "\fBFrom \fR", and appends an empty line.
 /*     The mailbox is locked for exclusive access while delivery is in
 /*     progress. In case of problems, an attempt is made to truncate the
 /*     mailbox to its original length.
 /*
 /*     In the case of \fBmaildir\fR delivery, the local daemon prepends
-/*     a \fBDelivered-To:\fR header with the envelope recipient address.
-/*     The envelope sender address is available in the \fBReturn-Path:\fR
-/*     header.
+/*     a \fBDelivered-To:\fR header with the envelope recipient address
+/*     and prepends a \fBReturn-Path:\fR header with the envelope sender
+/*     address.
 /* EXTERNAL COMMAND DELIVERY
 /* .ad
 /* .fi
 /*
 /*     The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
 /*     envelope header to each message, prepends a \fBDelivered-To:\fR
-/*     header with the recipient envelope address, and appends an empty line.
-/*     The envelope sender address is available in the \fBReturn-Path:\fR
-/*     header.
+/*     header with the recipient envelope address, prepends a
+/*     \fBReturn-Path:\fR header with the sender envelope address,
+/*     and appends an empty line.
 /* EXTERNAL FILE DELIVERY
 /* .ad
 /* .fi
 /* .fi
 /* .IP \fBalias_maps\fR
 /*     List of alias databases.
-/* .IP \fBhome_mailbox\fR
-/*     Pathname of a mailbox relative to a user's home directory.
-/*     Specify a path ending in \fB/\fR for maildir-style delivery.
 /* .IP \fBlocal_command_shell\fR
 /*     Shell to use for external command execution (for example,
 /*     /some/where/smrsh -c).
 /*     When a shell is specified, it is invoked even when the command
 /*     contains no shell built-in commands or meta characters.
-/* .IP \fBmailbox_command\fR
-/*     External command to use for mailbox delivery.
 /* .IP \fBowner_request_special\fR
 /*     Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
 /*     addresses.
 /* .IP \fBrecipient_delimiter\fR
 /*     Separator between username and address extension.
+/* .SH Mailbox delivery
+/* .ad
+/* .fi
+/* .IP \fBfallback_transport\fR
+/*     Message transport for recipients that are not found in the UNIX
+/*     passwd database.
+/*     This parameter overrides \fBluser_relay\fR.
+/* .IP \fBhome_mailbox\fR
+/*     Pathname of a mailbox relative to a user's home directory.
+/*     Specify a path ending in \fB/\fR for maildir-style delivery.
+/* .IP \fBluser_relay\fR
+/*     Destination (\fI@domain\fR or \fIaddress\fR) for non-existent users.
+/*     The \fIaddress\fR can be any destination that is valid in an alias
+/*     file.
+/* .IP \fBmail_spool_directory\fR
+/*     Directory with UNIX-style mailboxes. The default pathname is system
+/*     dependent.
+/* .IP \fBmailbox_command\fR
+/*     External command to use for mailbox delivery. The command executes
+/*     with the recipient privileges (exception: root).
+/* .IP \fBmailbox_transport\fR
+/*     Message transport to use for mailbox delivery to all local
+/*     recipients, whether or not they are found in the UNIX passwd database.
+/*     This parameter overrides all other configuration parameters that
+/*     control mailbox delivery, including \fBluser_relay\fR.
 /* .SH "Locking controls"
 /* .ad
 /* .fi
 #include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
+#ifdef USE_PATHS_H
+#include <paths.h>
+#endif
 
 /* Utility library. */
 
 #include <mail_addr.h>
 #include <config.h>
 #include <been_here.h>
+#include <mail_params.h>
 
 /* Single server skeleton. */
 
@@ -326,7 +365,11 @@ char   *var_home_mailbox;
 char   *var_mailbox_command;
 char   *var_rcpt_fdelim;
 char   *var_local_cmd_shell;
+char   *var_luser_relay;
 int     var_biff;
+char   *var_mail_spool_dir;
+char   *var_mailbox_transport;
+char   *var_fallback_transport;
 
 int     local_cmd_deliver_mask;
 int     local_file_deliver_mask;
@@ -376,6 +419,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
     RESET_OWNER_ATTR(state.msg_attr, state.level);
     RESET_USER_ATTR(usr_attr, state.level);
     state.loop_info = delivered_init(state.msg_attr);  /* delivered-to */
+    state.request = rqst;
 
     /*
      * Iterate over each recipient named in the delivery request. When the
@@ -480,6 +524,10 @@ int     main(int argc, char **argv)
        VAR_ALLOW_FILES, DEF_ALLOW_FILES, &var_allow_files, 0, 0,
        VAR_RCPT_FDELIM, DEF_RCPT_FDELIM, &var_rcpt_fdelim, 0, 0,
        VAR_LOCAL_CMD_SHELL, DEF_LOCAL_CMD_SHELL, &var_local_cmd_shell, 0, 0,
+       VAR_LUSER_RELAY, DEF_LUSER_RELAY, &var_luser_relay, 0, 0,
+       VAR_MAIL_SPOOL_DIR, DEF_MAIL_SPOOL_DIR, &var_mail_spool_dir, 0, 0,
+       VAR_MAILBOX_TRANSP, DEF_MAILBOX_TRANSP, &var_mailbox_transport, 0, 0,
+       VAR_FALLBACK_TRANSP, DEF_FALLBACK_TRANSP, &var_fallback_transport, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index a20b278525dd3e56730d3cc098e1f7756aa9e01c..ee4a884888c469c7d362dc0ea713fc387575a470 100644 (file)
@@ -20,6 +20,7 @@
   */
 #include <been_here.h>
 #include <tok822.h>
+#include <deliver_request.h>
 
  /*
   * User attributes: these control the privileges for delivery to external
@@ -97,6 +98,7 @@ typedef struct LOCAL_STATE {
     DELIVER_ATTR msg_attr;             /* message attributes */
     BH_TABLE *dup_filter;              /* internal duplicate filter */
     HTABLE *loop_info;                 /* external loop filter */
+    DELIVER_REQUEST *request;          /* as from queue manager */
 } LOCAL_STATE;
 
 #define RESET_OWNER_ATTR(msg_attr, level) { \
@@ -122,6 +124,12 @@ typedef struct LOCAL_STATE {
 #define OPENED_ATTR(attr)      attr.queue_id, attr.sender
 #define COPY_ATTR(attr)                attr.sender, attr.delivered, attr.fp
 
+#define MSG_LOG_STATE(m, s) \
+       msg_info("%s[%d]: local %s recip %s exten %s deliver %s", m, \
+                s.level, s.msg_attr.local, s.msg_attr.recipient, \
+               s.msg_attr.extension ? s.msg_attr.extension : "", \
+               s.msg_attr.delivered ? s.msg_attr.delivered : "")
+
  /*
   * "inner" nodes of the delivery graph.
   */
@@ -138,11 +146,12 @@ extern int deliver_resolve_addr(LOCAL_STATE, USER_ATTR, char *);
  /*
   * "leaf" nodes of the delivery graph.
   */
-extern int deliver_mailbox(LOCAL_STATE, USER_ATTR);
+extern int deliver_mailbox(LOCAL_STATE, USER_ATTR, int *);
 extern int deliver_command(LOCAL_STATE, USER_ATTR, char *);
 extern int deliver_file(LOCAL_STATE, USER_ATTR, char *);
 extern int deliver_indirect(LOCAL_STATE);
 extern int deliver_maildir(LOCAL_STATE, USER_ATTR, char *);
+extern int deliver_unknown(LOCAL_STATE, USER_ATTR);
 
  /*
   * Restrictions on delivery to sensitive destinations.
index 576bca22bb60a0a0b13cb6cbc0d7a06571ed682e..bb7d736b84413d89f95e3d090fa7ca33b55d0548 100644 (file)
@@ -6,9 +6,10 @@
 /* SYNOPSIS
 /*     #include "local.h"
 /*
-/*     int     deliver_mailbox(state, usr_attr)
+/*     int     deliver_mailbox(state, usr_attr, statusp)
 /*     LOCAL_STATE state;
 /*     USER_ATTR usr_attr;
+/*     int     *statusp;
 /* DESCRIPTION
 /*     deliver_mailbox() delivers to mailbox, with duplicate
 /*     suppression. The default is direct mailbox delivery to
@@ -17,6 +18,8 @@
 /*     and when a \fImailbox_command\fR has been configured, the message
 /*     is piped into the command instead.
 /*
+/*     A zero result means that the named user was not found.
+/*
 /*     Arguments:
 /* .IP state
 /*     The attributes that specify the message, recipient and more.
 /*     A table with the results from expanding aliases or lists.
 /* .IP usr_attr
 /*     Attributes describing user rights and environment.
+/* .IP statusp
+/*     Delivery status: see below.
 /* DIAGNOSTICS
-/*     deliver_mailbox() returns non-zero when delivery should be tried again,
+/*     The message delivery status is non-zero when delivery should be tried
+/*     again.
 /* LICENSE
 /* .ad
 /* .fi
@@ -44,9 +50,6 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
-#ifdef USE_PATHS_H
-#include <paths.h>
-#endif
 
 /* Utility library. */
 
 #ifdef USE_DOT_LOCK
 #include <dot_lockfile.h>
 #endif
-#include <bounce.h>
 #include <defer.h>
 #include <sent.h>
 #include <mypwd.h>
 #include <been_here.h>
 #include <mail_params.h>
+#include <mail_proto.h>
 
 /* Application-specific. */
 
 #include "local.h"
 #include "biff_notify.h"
 
+#define YES    1
+#define NO     0
+
 /* deliver_mailbox_file - deliver to recipient mailbox */
 
 static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
 {
+    char   *myname = "deliver_mailbox_file";
+    char   *spool_dir;
     char   *mailbox;
     VSTRING *why;
     VSTREAM *dst;
@@ -89,9 +97,18 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     int     copy_flags;
     VSTRING *biff;
     long    end;
+    struct stat st;
+    uid_t   spool_uid;
+    gid_t   spool_gid;
+    uid_t   chown_uid;
+    gid_t   chown_gid;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
     if (msg_verbose)
-       msg_info("deliver_mailbox_file: %s", state.msg_attr.recipient);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * Initialize. Assume the operation will fail. Set the delivered
@@ -102,29 +119,67 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     state.msg_attr.delivered = state.msg_attr.recipient;
     status = -1;
     why = vstring_alloc(100);
-    if (*var_home_mailbox)
+    if (*var_home_mailbox) {
+       spool_dir = 0;
        mailbox = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
-    else
-       mailbox = concatenate(_PATH_MAILDIR, "/", state.msg_attr.local, (char *) 0);
+    } else {
+       spool_dir = var_mail_spool_dir;
+       mailbox = concatenate(spool_dir, "/", state.msg_attr.local, (char *) 0);
+    }
+
+    /*
+     * Mailbox delivery with least privilege. As long as we do not use root
+     * privileges this code may also work over NFS.
+     * 
+     * If delivering to the recipient's home directory, perform all operations
+     * (including file locking) as that user (Mike Muuss, Army Research
+     * Laboratory, USA).
+     * 
+     * If delivering to the mail spool directory, and the spool directory is
+     * world-writable, deliver as the recipient; if the spool directory is
+     * group-writable, use the recipient user id and the mail spool group id.
+     * 
+     * Otherwise, use root privileges and chown the mailbox.
+     */
+    if (spool_dir == 0
+       || stat(spool_dir, &st) < 0
+       || (st.st_mode & S_IWOTH) != 0) {
+       spool_uid = usr_attr.uid;
+       spool_gid = usr_attr.gid;
+    } else if ((st.st_mode & S_IWGRP) != 0) {
+       spool_uid = usr_attr.uid;
+       spool_gid = st.st_gid;
+    } else {
+       spool_uid = 0;
+       spool_gid = 0;
+    }
+    if (spool_uid == usr_attr.uid) {
+       chown_uid = -1;
+       chown_gid = -1;
+    } else {
+       chown_uid = usr_attr.uid;
+       chown_gid = usr_attr.gid;
+    }
+    if (msg_verbose)
+       msg_info("spool_uid/gid %d/%d chown_uid/gid %d/%d",
+                spool_uid, spool_gid, chown_uid, chown_gid);
 
     /*
      * Lock the mailbox and open/create the mailbox file. Depending on the
      * type of locking used, we lock first or we open first.
      * 
      * Write the file as the recipient, so that file quota work.
-     * 
-     * Create lock files as root, for non-writable directories.
      */
     copy_flags = MAIL_COPY_MBOX;
     if (state.msg_attr.features & FEATURE_NODELIVERED)
        copy_flags &= ~MAIL_COPY_DELIVERED;
 
-    set_eugid(0, 0);
+    set_eugid(spool_uid, spool_gid);
 #ifdef USE_DOT_LOCK
     if (dot_lockfile(mailbox, why) >= 0) {
 #endif
        dst = safe_open(mailbox, O_APPEND | O_WRONLY | O_CREAT,
-                       S_IRUSR | S_IWUSR, usr_attr.uid, usr_attr.gid, why);
+                       S_IRUSR | S_IWUSR, chown_uid, chown_gid, why);
        set_eugid(usr_attr.uid, usr_attr.gid);
        if (dst != 0) {
            end = vstream_fseek(dst, (off_t) 0, SEEK_END);
@@ -143,7 +198,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
            }
        }
 #ifdef USE_DOT_LOCK
-       set_eugid(0, 0);
+       set_eugid(spool_uid, spool_gid);
        dot_unlockfile(mailbox);
     }
 #endif
@@ -161,7 +216,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
 
 /* deliver_mailbox - deliver to recipient mailbox */
 
-int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr)
+int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
 {
     char   *myname = "deliver_mailbox";
     int     status;
@@ -173,29 +228,30 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr)
      */
     state.level++;
     if (msg_verbose)
-       msg_info("%s[%d]: %s", myname, state.level, state.msg_attr.recipient);
-
-    /*
-     * Strip quoting that was prepended to defeat alias/forward expansion.
-     */
-    if (state.msg_attr.recipient[0] == '\\')
-       state.msg_attr.recipient++, state.msg_attr.local++;
+       MSG_LOG_STATE(myname, state);
 
     /*
      * DUPLICATE ELIMINATION
      * 
-     * Don't deliver more than once to this mailbox.
+     * Don't come here more than once, whether or not the recipient exists.
      */
     if (been_here(state.dup_filter, "mailbox %s", state.msg_attr.local))
-       return (0);
+       return (YES);
+
+    /*
+     * Delegate mailbox delivery to another message transport.
+     */
+    if (*var_mailbox_transport) {
+       *statusp = deliver_pass(MAIL_CLASS_PRIVATE, var_mailbox_transport,
+                             state.request, state.msg_attr.recipient, -1L);
+       return (YES);
+    }
 
     /*
-     * Bounce the message when this recipient does not exist. XXX Should
-     * quote_822_local() the recipient.
+     * Skip delivery when this recipient does not exist.
      */
     if ((mbox_pwd = mypwnam(state.msg_attr.local)) == 0)
-       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
-                             "unknown user: \"%s\"", state.msg_attr.local));
+       return (NO);
 
     /*
      * No early returns or we have a memory leak.
@@ -209,7 +265,7 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr)
     SET_USER_ATTR(usr_attr, mbox_pwd, state.level);
 
     /*
-     * Deliver to mailbox or to external delivery agent.
+     * Deliver to mailbox or to external command.
      */
 #define LAST_CHAR(s) (s[strlen(s) - 1])
 
@@ -226,5 +282,6 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr)
      * Cleanup.
      */
     mypwfree(mbox_pwd);
-    return (status);
+    *statusp = status;
+    return (YES);
 }
index 0cbad5a9b0abc18879b831096f2142a8c2a75ed6..50d8436064eb39796ad3d483c06098d7ad08e1e8 100644 (file)
@@ -69,6 +69,7 @@
 
 int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
 {
+    char   *myname = "deliver_maildir";
     char   *newdir;
     char   *tmpdir;
     char   *curdir;
@@ -81,8 +82,12 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     int     copy_flags;
     static int count;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
     if (msg_verbose)
-       msg_info("deliver_maildir: %s %s", state.msg_attr.recipient, path);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * Initialize. Assume the operation will fail. Set the delivered
@@ -95,7 +100,7 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
     buf = vstring_alloc(100);
     why = vstring_alloc(100);
 
-    copy_flags = MAIL_COPY_TOFILE;
+    copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH;
     if ((state.msg_attr.features & FEATURE_NODELIVERED) == 0)
        copy_flags |= MAIL_COPY_DELIVERED;
 
@@ -133,7 +138,7 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
        if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, why) == 0) {
            if (link(tmpfile, newfile) < 0
                && (errno != ENOENT
-                   || (make_dirs(curdir,0700), make_dirs(newdir, 0700)) < 0
+                   || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
                    || link(tmpfile, newfile) < 0)) {
                vstring_sprintf(why, "link to %s: %m", newfile);
            } else {
index fd68fc1a3d75d35ab3c83587194b8bdd575743c3..8456b72fdf030abf74d0807bb3b0d97393111412 100644 (file)
@@ -79,7 +79,6 @@
 /* Global library. */
 
 #include <bounce.h>
-#include <defer.h>
 #include <mail_params.h>
 #include <split_addr.h>
 
 
 static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
 {
+    char   *myname = "deliver_switch";
     int     status;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
+    if (msg_verbose)
+       MSG_LOG_STATE(myname, state);
+
+
     /*
      * \user is special: it means don't do any alias or forward expansion.
      */
-    if (state.msg_attr.recipient[0] == '\\')
-       return (deliver_mailbox(state, usr_attr));
+    if (state.msg_attr.recipient[0] == '\\') {
+       state.msg_attr.recipient++;
+       if (*var_rcpt_delim)
+           state.msg_attr.extension =
+               split_addr(state.msg_attr.local, *var_rcpt_delim);
+       if (deliver_mailbox(state, usr_attr, &status) == 0)
+           status = deliver_unknown(state, usr_attr);
+       return (status);
+    }
 
     /*
      * Otherwise, alias expansion has highest precedence.
@@ -137,10 +152,11 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
 
     /*
      * Delivery to local user. First try expansion of the recipient's
-     * $HOME/.forward file. Do mailbox delivery as a last resort.
+     * $HOME/.forward file, then mailbox delivery.
      */
-    if (deliver_dotforward(state, usr_attr, &status) == 0)
-       status = deliver_mailbox(state, usr_attr);
+    if (deliver_dotforward(state, usr_attr, &status) == 0
+       && deliver_mailbox(state, usr_attr, &status) == 0)
+       status = deliver_unknown(state, usr_attr);
     return (status);
 }
 
@@ -148,10 +164,15 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
 
 int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
 {
+    char   *myname = "deliver_recipient";
     int     rcpt_stat;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
     if (msg_verbose)
-       msg_info("deliver_recipient: %s", state.msg_attr.recipient);
+       MSG_LOG_STATE(myname, state);
 
     /*
      * With each level of recursion, detect and break external message
@@ -173,6 +194,7 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
        msg_warn("no @ in recipient address: %s", state.msg_attr.local);
     lowercase(state.msg_attr.local);
     state.msg_attr.features = feature_control(state.msg_attr.local);
+    state.msg_attr.extension = 0;
 
     /*
      * Run the recipient through the delivery switch.
index d7682490439ad6db2117797ee09161722dea5493..2e0f339da1ef8b2c404a08174b0d002470692446 100644 (file)
@@ -86,11 +86,19 @@ int     deliver_resolve_addr(LOCAL_STATE state, USER_ATTR usr_attr, char *addr)
 
 int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
 {
+    char   *myname = "deliver_resolve_tree";
     RESOLVE_REPLY reply;
     int     status;
     int     ext_len;
     char   *ratsign;
 
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
+    if (msg_verbose)
+       MSG_LOG_STATE(myname, state);
+
     /*
      * Initialize.
      */
diff --git a/postfix/local/unknown.c b/postfix/local/unknown.c
new file mode 100644 (file)
index 0000000..0689289
--- /dev/null
@@ -0,0 +1,182 @@
+/*++
+/* NAME
+/*     unknown 3
+/* SUMMARY
+/*     delivery of unknown recipients
+/* SYNOPSIS
+/*     #include "local.h"
+/*
+/*     int     deliver_unknown(state, usr_attr)
+/*     LOCAL_STATE state;
+/*     USER_ATTR usr_attr;
+/* DESCRIPTION
+/*     deliver_unknown() delivers a message for unknown recipients.
+/* .IP \(bu
+/*     If an alternative message transport is specified via the
+/*     fallback_transport parameter, delivery is delegated to the
+/*     named transport.
+/* .IP \(bu
+/*     If an alternative address is specified via the luser_relay 
+/*     configuration parameter, mail is forwarded to that address.
+/* .IP \(bu
+/*     Otherwise the recipient is bounced.
+/* .PP
+/*     If the luser_relay parameter specifies a @domain, the entire
+/*     original recipient localpart is prepended. For example: with
+/*     "luser_relay = @some.where", unknown+foo becomes
+/*     unknown+foo@some.where.
+/*
+/*     Otherwise, the luser_relay parameter can specify any number of
+/*     destinations that are valid in an alias file or in a .forward file.
+/*     For example, a destination could be an address, a "|command" or
+/*     a /file/name. The luser_relay feature is treated as an alias, and
+/*     the usual restrictions for command and file destinations apply.
+/*
+/*     If the luser_relay destination is a mail address, and the
+/*     recipient delimiter has been defined, the entire original recipient
+/*     localpart is appended as an address extension. For example: with
+/*     "luser_relay = someone@some.where", unknown+foo becomes
+/*     someone+unknown+foo@some.where.
+/*
+/*     Arguments:
+/* .IP state
+/*     Message delivery attributes (sender, recipient etc.).
+/*     Attributes describing alias, include or forward expansion.
+/*     A table with the results from expanding aliases or lists.
+/*     A table with delivered-to: addresses taken from the message.
+/* .IP usr_attr
+/*     Attributes describing user rights and environment.
+/* DIAGNOSTICS
+/*     The result status is non-zero when delivery should be tried again.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <stringops.h>
+#include <mymalloc.h>
+
+/* Global library. */
+
+#include <been_here.h>
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <bounce.h>
+
+/* Application-specific. */
+
+#include "local.h"
+
+/* deliver_unknown - delivery for unknown recipients */
+
+int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
+{
+    char   *myname = "deliver_unknown";
+    int     status;
+    char   *dest;
+    char   *saved_extension;
+
+    /*
+     * Make verbose logging easier to understand.
+     */
+    state.level++;
+    if (msg_verbose)
+       MSG_LOG_STATE(myname, state);
+
+    /*
+     * DUPLICATE/LOOP ELIMINATION
+     * 
+     * Don't deliver the same user twice.
+     */
+    if (been_here(state.dup_filter, "%s %s", myname, state.msg_attr.local))
+       return (0);
+
+    /*
+     * The fall-back transport specifies a delivery machanism that handles
+     * users not found in the aliases or UNIX passwd databases.
+     */
+    if (*var_fallback_transport)
+       return (deliver_pass(MAIL_CLASS_PRIVATE, var_fallback_transport,
+                            state.request, state.msg_attr.recipient, -1L));
+
+    /*
+     * Bounce the message when no luser relay is specified.
+     */
+    if (*var_luser_relay == 0)
+       return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+                             "unknown user: \"%s\"", state.msg_attr.local));
+
+    /*
+     * EXTERNAL LOOP CONTROL
+     * 
+     * Set the delivered message attribute to the recipient, so that this
+     * message will list the correct forwarding address.
+     */
+    state.msg_attr.delivered = state.msg_attr.recipient;
+
+    /*
+     * DELIVERY POLICY
+     * 
+     * The luser relay is just another alias. Update the expansion type
+     * attribute, so we can decide if deliveries to |command and /file/name
+     * are allowed at all.
+     */
+    state.msg_attr.exp_type = EXPAND_TYPE_ALIAS;
+
+    /*
+     * DELIVERY RIGHTS
+     * 
+     * What rights to use for |command and /file/name deliveries? The luser
+     * relay is a root-owned alias, so we use default rights.
+     */
+    RESET_USER_ATTR(usr_attr, state.level);
+
+    /*
+     * If the luser destination is specified as @domain, prepend the
+     * localpart. The local resolver will append the optional address
+     * extension, so we don't do that here.
+     */
+    if (*var_luser_relay == '@') {             /* @domain */
+       dest = concatenate(state.msg_attr.local, var_luser_relay, (char *) 0);
+       status = deliver_token_string(state, usr_attr, dest, (int *) 0);
+       myfree(dest);
+    }
+
+    /*
+     * Otherwise, optionally arrange for the local resolver to append the
+     * entire localpart, including the optional address extension, to the
+     * destination localpart.
+     */
+    else {                                     /* other */
+       if ((saved_extension = state.msg_attr.extension) != 0)
+           state.msg_attr.extension = concatenate(state.msg_attr.local,
+                                                  var_rcpt_delim,
+                                                  state.msg_attr.extension,
+                                                  (char *) 0);
+       else if (*var_rcpt_delim)
+           state.msg_attr.extension = state.msg_attr.local;
+       status = deliver_token_string(state, usr_attr, var_luser_relay,
+                                     (int *) 0);
+       if (saved_extension != 0)
+           myfree(state.msg_attr.extension);
+       state.msg_attr.extension = saved_extension;
+    }
+
+    /*
+     * Done.
+     */
+    return (status);
+}
index 47ce8a5f99849238cd35c55843973c7e1e27ad92..61274aebf49d2cfb72b17a34dcbb812bdfef7f38 100644 (file)
@@ -59,10 +59,22 @@ case "$SYSTEM.$RELEASE" in
                RANLIB=echo
                SYSLIBS="-lresolv -lsocket -lnsl"
                ;;
+  UNIX_SV.4.2*)        case "`uname -v`" in
+             2.1*) SYSTYPE=UW21
+                   CC=/usr/bin/cc
+                   RANLIB=echo
+                   SYSLIBS="-lresolv -lsocket -lnsl -lc -L/usr/ucblib -lucb"
+                   ;;
+             *) echo "Seems to be UnixWare`uname -v`. Untested." 1>&2; 
+                exit 1;;
+               esac
+               ;;
   FreeBSD.2*)  SYSTYPE=FREEBSD2
                ;;
   FreeBSD.3*)  SYSTYPE=FREEBSD3
                ;;
+  FreeBSD.4*)  SYSTYPE=FREEBSD4
+               ;;
   OpenBSD.2*)  SYSTYPE=OPENBSD2
                ;;
    NetBSD.1*)  SYSTYPE=NETBSD1
@@ -109,6 +121,7 @@ case "$SYSTEM.$RELEASE" in
                        case "$CC" in
                        cc|*/cc|xlc|*/xlc) OPT=;;
                        esac
+                       CCARGS="$CCARGS -D_ALL_SOURCE"
                        ;;
                *)      echo "Unknown AIX version: `uname -v`." 1>&2; exit 1;;
                esac;;
index 953a869368f4c28e6b4541a6bef1b52307b69cf0..01f1e374d05a1cd4fca0b7faabcd2fd02f427df1 100644 (file)
@@ -5,7 +5,8 @@ DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/local.8 \
        man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.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
+       man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
+       man1/postsuper.1
 CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \
        man5/transport.5 man5/virtual.5
 
@@ -85,6 +86,9 @@ man1/postlog.1: ../postlog/postlog.c
 man1/postmap.1: ../postmap/postmap.c
        srctoman $? >$@
 
+man1/postsuper.1: ../postsuper/postsuper.c
+       srctoman $? >$@
+
 man1/sendmail.1: ../sendmail/sendmail.c
        srctoman $? >$@
 
index bc34bcd0c626aedac3facdf068449062f24214b0..4f386a6d3f6e46962aea24331a22e16a8bdbeb77 100644 (file)
@@ -9,16 +9,21 @@ Postfix configuration utility
 .na
 .nf
 .fi
-\fBpostconf\fR [\fB-d\fR] [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
+\fBpostconf\fR [\fB-d\fR] [\fB-h\fR] [\fB-n\fR] [\fB-v\fR]
+[\fIparameter ...\fR]
 .SH DESCRIPTION
 .ad
 .fi
 The \fBpostconf\fR command prints the actual value of
-\fIparameter\fR (all known parameters by default).
+\fIparameter\fR (all known parameters by default), one
+parameter per line.
 
 Options:
 .IP \fB-d\fR
 Print default parameter settings instead of actual settings.
+.IP \fB-h\fR
+Show parameter values only, not the \fIname =\fR information
+that normally precedes the value.
 .IP \fB-n\fR
 Print non-default parameter settings only.
 .IP \fB-v\fR
index e76860f1f402d3493ba50cb28841244817a26e9b..42a67bbf9e74d68632a95f7f605873d7943a5fb0 100644 (file)
@@ -20,7 +20,7 @@ group write permission to the \fBmaildrop\fR queue directory.
 
 The \fBpostdrop\fR command is automatically invoked by the
 \fBsendmail\fR(1) mail posting agent when the \fBmaildrop\fR
-queue directory is not writable.
+queue directory is not world-writable.
 
 Options:
 .IP \fB-v\fR
diff --git a/postfix/man/man1/postsuper.1 b/postfix/man/man1/postsuper.1
new file mode 100644 (file)
index 0000000..996a0a9
--- /dev/null
@@ -0,0 +1,68 @@
+.TH POSTSUPER 1 
+.ad
+.fi
+.SH NAME
+postsuper
+\-
+Postfix super intendent
+.SH SYNOPSIS
+.na
+.nf
+.fi
+\fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
+.SH DESCRIPTION
+.ad
+.fi
+The \fBpostsuper\fR command does small maintenance jobs on the named
+Postfix queue directories (default: all).
+Directory names are relative to the Postfix top-level queue directory.
+
+By default, \fBpostsuper\fR performs the operations requested with the
+\fB-s\fR and \fB-p\fR command-line options.
+\fBpostsuper\fR always tries to remove objects that are neither files
+nor directories.  Use of this command is restricted to the super-user.
+
+Options:
+.IP \fB-s\fR
+Structure check.  Move queue files that are in the wrong place
+in the file system hierarchy and remove subdirectories that are
+no longer needed. File rearrangements are necessary after a change
+in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
+configuration parameters. It is highly recommended to run this
+check once before Postfix startup.
+.IP \fB-p\fR
+Purge stale files (files that are left over after system or
+software crashes).
+.IP \fB-v\fR
+Enable verbose mode for debugging purposes. Multiple \fB-v\fR
+options make the software increasingly verbose.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems are reported to the standard error stream and to
+\fBsyslogd\fR.
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.ad
+.fi
+See the Postfix \fBmain.cf\fR file for syntax details and for
+default values.
+.IP \fBhash_queue_depth\fR
+Number of subdirectory levels for hashed queues.
+.IP \fBhash_queue_names\fR
+The names of queues that are organized into multiple levels of
+subdirectories.
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 287debf45ea84b496a9c9a11ee47c83811c5360b..1c60645a97d5e2b67f5c8d4b8b56aff2bc7d5b0f 100644 (file)
@@ -25,8 +25,8 @@ Sendmail command-line options are recognized but silently ignored.
 
 By default, \fBsendmail\fR reads a message from standard input
 and arranges for delivery.  \fBsendmail\fR attempts to create
-a queue file in the \fBmaildrop\fR directory. If the process has
-no write permission, the message is piped through the
+a queue file in the \fBmaildrop\fR directory. If that directory
+is not world-writable, the message is piped through the
 \fBpostdrop\fR(1) command, which is expected to execute with
 suitable privileges.
 
@@ -118,6 +118,10 @@ The sender is never eliminated from alias etc. expansions.
 .IP "\fB-o \fIx value\fR (ignored)"
 Set option \fIx\fR to \fIvalue\fR. Use the equivalent
 configuration parameter in \fBmain.cf\fR instead.
+.IP "\fB-r \fIsender\fR"
+Set the envelope sender address. This is the address where
+delivery problems are sent to, unless the message contains an
+\fBErrors-To:\fR message header.
 .IP \fB-q\fR
 Flush the mail queue. This is implemented by kicking the
 \fBqmgr\fR(8) daemon.
index 4fd9efaa45276c07b531c82552239dde848e2114..d16dbd529b6be13510e7e4cf40f42bcc053f0cf0 100644 (file)
@@ -74,29 +74,44 @@ mail arrives for a recipient that is already listed in a
 .nf
 .ad
 .fi
-The per-user mailbox is either a file in the default UNIX mailbox
-directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR)
-or it is a file in the user's home directory with a name specified
-via the \fBhome_mailbox\fR configuration parameter. Specify a path
-name ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR
-delivery.
+The default per-user mailbox is a file in the UNIX mail spool
+directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR);
+the location can be specified with the \fBmail_spool_directory\fR
+configuration parameter.
+
+Alternatively, the per-user mailbox can be a file in the user's home
+directory with a name specified via the \fBhome_mailbox\fR
+configuration parameter. Specify a relative path name. Specify a name
+ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR delivery.
+
 Mailbox delivery can be delegated to an external command specified
-with the \fBmailbox_command\fR configuration parameter.
+with the \fBmailbox_command\fR configuration parameter. The command
+executes with the privileges of the recipient user (exception: in
+case of delivery as root, the command executes with the privileges
+of \fBdefault_user\fR).
 
-The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
+Mailbox delivery can be delegated to alternative message transports
+specified in the \fBmaster.cf\fR file.
+The \fBmailbox_transport\fR configuration parameter specifies a
+message transport that is to be used for all local recipients,
+regardless of whether they are found in the UNIX passwd database.
+The \fBfallback_transport\fR parameter specifies a message transport
+for recipients that are not found in the UNIX passwd database.
+
+In the case of UNIX-style mailbox delivery,
+the \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
 envelope header to each message, prepends a \fBDelivered-To:\fR header
-with the envelope recipient address, prepends a \fB>\fR character to
-lines beginning with "\fBFrom \fR", and appends an empty line.
-The envelope sender address is available in the \fBReturn-Path:\fR
-header.
+with the envelope recipient address, prepends a \fBReturn-Path:\fR
+header with the envelope sender address, prepends a \fB>\fR character
+to lines beginning with "\fBFrom \fR", and appends an empty line.
 The mailbox is locked for exclusive access while delivery is in
 progress. In case of problems, an attempt is made to truncate the
 mailbox to its original length.
 
 In the case of \fBmaildir\fR delivery, the local daemon prepends
-a \fBDelivered-To:\fR header with the envelope recipient address.
-The envelope sender address is available in the \fBReturn-Path:\fR
-header.
+a \fBDelivered-To:\fR header with the envelope recipient address
+and prepends a \fBReturn-Path:\fR header with the envelope sender
+address.
 .SH EXTERNAL COMMAND DELIVERY
 .na
 .nf
@@ -128,9 +143,9 @@ The current working directory is the mail queue directory.
 
 The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR"
 envelope header to each message, prepends a \fBDelivered-To:\fR
-header with the recipient envelope address, and appends an empty line.
-The envelope sender address is available in the \fBReturn-Path:\fR
-header.
+header with the recipient envelope address, prepends a
+\fBReturn-Path:\fR header with the sender envelope address,
+and appends an empty line.
 .SH EXTERNAL FILE DELIVERY
 .na
 .nf
@@ -225,21 +240,41 @@ a configuration change.
 .fi
 .IP \fBalias_maps\fR
 List of alias databases.
-.IP \fBhome_mailbox\fR
-Pathname of a mailbox relative to a user's home directory.
-Specify a path ending in \fB/\fR for maildir-style delivery.
 .IP \fBlocal_command_shell\fR
 Shell to use for external command execution (for example,
 /some/where/smrsh -c).
 When a shell is specified, it is invoked even when the command
 contains no shell built-in commands or meta characters.
-.IP \fBmailbox_command\fR
-External command to use for mailbox delivery.
 .IP \fBowner_request_special\fR
 Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
 addresses.
 .IP \fBrecipient_delimiter\fR
 Separator between username and address extension.
+.SH Mailbox delivery
+.ad
+.fi
+.IP \fBfallback_transport\fR
+Message transport for recipients that are not found in the UNIX
+passwd database.
+This parameter overrides \fBluser_relay\fR.
+.IP \fBhome_mailbox\fR
+Pathname of a mailbox relative to a user's home directory.
+Specify a path ending in \fB/\fR for maildir-style delivery.
+.IP \fBluser_relay\fR
+Destination (\fI@domain\fR or \fIaddress\fR) for non-existent users.
+The \fIaddress\fR can be any destination that is valid in an alias
+file.
+.IP \fBmail_spool_directory\fR
+Directory with UNIX-style mailboxes. The default pathname is system
+dependent.
+.IP \fBmailbox_command\fR
+External command to use for mailbox delivery. The command executes
+with the recipient privileges (exception: root).
+.IP \fBmailbox_transport\fR
+Message transport to use for mailbox delivery to all local
+recipients, whether or not they are found in the UNIX passwd database.
+This parameter overrides all other configuration parameters that
+control mailbox delivery, including \fBluser_relay\fR.
 .SH "Locking controls"
 .ad
 .fi
index 8cf9fd3d765e660ca1f3c1c8933a88a11a655758..eaf281c4c9976337ec698a1557cc49d67e33c915 100644 (file)
@@ -111,6 +111,8 @@ Limit the time in seconds that a child process waits between
 service requests.
 .IP \fBmax_use\fR
 Limit the number of service requests handled by a child process.
+.IP \fBservice_throttle_time\fR
+Time to avoid forking a server that appears to be broken.
 .SH FILES
 .na
 .nf
index 5b17e81d0f1def82f5638d646e1f546233a424f3..a54291acfa700aa12f1f7ce1aa924e8fcb2cbc45 100644 (file)
@@ -59,6 +59,8 @@ a configuration change.
 .SH Miscellaneous
 .ad
 .fi
+.IP \fBalways_bcc\fR
+Address to send a copy of each message that enters the system.
 .IP \fBmail_owner\fR
 The process privileges used while not opening a \fBmaildrop\fR file.
 .IP \fBqueue_directory\fR
index df6a6ef392b5649a5aa4369213d5a84a87975965..f602d935bc52b8da7eff4d96a8bee3e711276bbc 100644 (file)
@@ -30,7 +30,7 @@ to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
 .fi
 The external command attributes are given in the \fBmaster.cf\fR
 file at the end of a service definition.  The syntax is as follows:
-.IP "\fBflags=F>\fR (optional)"
+.IP "\fBflags=FR>\fR (optional)"
 Optional message processing flags. By default, a message is
 copied unchanged.
 .RS
@@ -39,15 +39,21 @@ Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
 the message content.
 This is expected by, for example, \fBUUCP\fR software. The \fBF\fR
 flag also causes an empty line to be appended to the message.
+.IP \fBR\fR
+Prepend a \fBReturn-Path:\fR message header with the envelope sender
+address.
 .IP \fB>\fR
-Prepend \fB>\fR to lines starting with "\fBFrom \fR". This expected
+Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
 by, for example, \fBUUCP\fR software.
 .RE
 .IP "\fBuser\fR=\fIusername\fR (required)"
+.IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
 The external command is executed with the rights of the
 specified \fIusername\fR.  The software refuses to execute
 commands with root privileges, or with the privileges of the
-mail system owner.
+mail system owner. If \fIgroupname\fR is specified, the
+corresponding group ID is used instead of the group ID of
+of \fIusername\fR.
 .IP "\fBargv\fR=\fIcommand\fR... (required)"
 The command to be executed. This must be specified as the
 last command attribute.
index e18309f07cb7e9ee9884d22954c36c93da171083..4e799bd4ac731b866727bb42664b34d24cbe40d2 100644 (file)
@@ -82,12 +82,10 @@ of new mail.
 .IP "\fBslow start\fR"
 This strategy eliminates "thundering herd" problems by slowly
 adjusting the number of parallel deliveries to the same destination.
-.IP "\fBround robin\fR and \fBrandom walk\fR"
+.IP "\fBround robin\fR
 The queue manager sorts delivery requests by destination.
 Round-robin selection prevents one destination from dominating
 deliveries to other destinations.
-Random walk prevents one problematic message from blocking
-deliveries of other mail to the same destination.
 .IP "\fBexponential backoff\fR"
 Mail that cannot be delivered upon the first attempt is deferred.
 The time interval between delivery attempts is doubled after each
index d41894ebd3eff72391b77ef43e795c5ca1da2857..38093ac2bca3541878a8fa84e0eb1b7a7d24e7e8 100644 (file)
@@ -78,6 +78,12 @@ pattern in the \fBdebug_peer_list\fR parameter.
 List of domain or network patterns. When a remote host matches
 a pattern, increase the verbose logging level by the amount
 specified in the \fBdebug_peer_level\fR parameter.
+.IP \fBfallback_relay\fR
+Hosts to hand off mail to if a message destination is not found
+or if a destination is unreachable.
+.IP \fBignore_mx_lookup_error\fR
+When a name server fails to respond to an MX query, search for an
+A record instead of assuming that the name server will recover.
 .IP \fBinet_interfaces\fR
 The network interface addresses that this mail system receives
 mail on. When any of those addresses appears in the list of mail
@@ -86,6 +92,10 @@ avoid mail delivery loops.
 .IP \fBnotify_classes\fR
 When this parameter includes the \fBprotocol\fR class, send mail to the
 postmaster with transcripts of SMTP sessions with protocol errors.
+.IP \fBsmtp_skip_4xx_greeting\fR
+Skip servers that greet us with a 4xx status code.
+.IP \fBsmtp_skip_quit_response\fR
+Do not wait for the server response after sending QUIT.
 .SH "Resource controls"
 .ad
 .fi
index af86f29f0384b3eacb8be61d6de291a11bbd58d1..c838208b34148fe509e205c8bd9bc02399155d6e 100644 (file)
@@ -71,6 +71,8 @@ a configuration change.
 .SH Miscellaneous
 .ad
 .fi
+.IP \fBalways_bcc\fR
+Address to send a copy of each message that enters the system.
 .IP \fBcommand_directory\fR
 Location of Postfix support commands (default:
 \fB$program_directory\fR).
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 56bbaf13c7d404e6681efb750db39df26be97ce7..dcf254d15670ef1df8795e2d4ef388a5efb7c768 100644 (file)
@@ -199,6 +199,8 @@ multi_server.o: ../include/msg_vstream.h
 multi_server.o: ../include/mymalloc.h
 multi_server.o: ../include/stringops.h
 multi_server.o: ../include/sane_accept.h
+multi_server.o: ../include/myflock.h
+multi_server.o: ../include/safe_open.h
 multi_server.o: ../include/mail_task.h
 multi_server.o: ../include/debug_process.h
 multi_server.o: ../include/mail_params.h
@@ -221,6 +223,8 @@ single_server.o: ../include/events.h
 single_server.o: ../include/iostuff.h
 single_server.o: ../include/stringops.h
 single_server.o: ../include/sane_accept.h
+single_server.o: ../include/myflock.h
+single_server.o: ../include/safe_open.h
 single_server.o: ../include/mail_params.h
 single_server.o: ../include/mail_task.h
 single_server.o: ../include/debug_process.h
@@ -243,6 +247,8 @@ trigger_server.o: ../include/events.h
 trigger_server.o: ../include/iostuff.h
 trigger_server.o: ../include/stringops.h
 trigger_server.o: ../include/sane_accept.h
+trigger_server.o: ../include/myflock.h
+trigger_server.o: ../include/safe_open.h
 trigger_server.o: ../include/mail_params.h
 trigger_server.o: ../include/mail_task.h
 trigger_server.o: ../include/debug_process.h
index 883fd9218fc60e3fd3ff04dd13e33057dff13e0e..ed7043e336abb0c9b32af271367ebd30361a365e 100644 (file)
 #define        MAIL_SERVER_PRE_INIT    10
 #define MAIL_SERVER_POST_INIT  11
 #define MAIL_SERVER_LOOP       12
+#define MAIL_SERVER_EXIT       13
 
 typedef void (*MAIL_SERVER_INIT_FN) (void);
 typedef int (*MAIL_SERVER_LOOP_FN) (void);
+typedef void (*MAIL_SERVER_EXIT_FN) (void);
 
  /*
   * single_server.c
index fba9d1fe3a56cc5d3017d87f745d1dcb7cb6512a..2f78b3d1c3ed57f9718de44fad9eb1ede4698ce6 100644 (file)
@@ -97,6 +97,8 @@
 /*     service requests.
 /* .IP \fBmax_use\fR
 /*     Limit the number of service requests handled by a child process.
+/* .IP \fBservice_throttle_time\fR
+/*     Time to avoid forking a server that appears to be broken.
 /* FILES
 /*     /etc/postfix/main.cf: global configuration file.
 /*     /etc/postfix/master.cf: master process configuration file.
index 6ca860bd288df4c32bcf1a8251408b65ee0b4b23..f09af8770c54a7ebbc77ebbcbc8f0bfcc630a975 100644 (file)
@@ -62,8 +62,6 @@ typedef struct MASTER_SERV {
   * manager runs at high privilege level and has to be kept simple.
   */
 #define MASTER_DEF_MIN_IDLE    1       /* preferred # of idle processes */
-#define MASTER_DEF_MAX_PROC    100     /* max # of processes within service */
-#define MASTER_DEF_THROTTLE_DELAY 100  /* fork delay when in trouble */
 
  /*
   * Structure of child process.
index e0bde144add1491f77bc3459aed463bc11e8711c..b0f451c909b10ce2898bcab39762aaf1d4b36e9f 100644 (file)
@@ -360,7 +360,7 @@ MASTER_SERV *get_master_ent()
     /*
      * Backoff time in case a service is broken.
      */
-    serv->throttle_delay = MASTER_DEF_THROTTLE_DELAY;  /* XXX config */
+    serv->throttle_delay = var_throttle_time;
 
     /*
      * Shared channel for child status updates.
@@ -378,6 +378,8 @@ MASTER_SERV *get_master_ent()
      */
     serv->args = argv_alloc(0);
     argv_add(serv->args, command, (char *) 0);
+    if (serv->max_proc == 1)
+       argv_add(serv->args, "-l", (char *) 0);
     if (strcmp(basename(command), name) != 0)
        argv_add(serv->args, "-n", name, (char *) 0);
     argv_add(serv->args, "-t", transport, (char *) 0);
index 4931cb9c2e6073f3516f351dff2c28f35edfe6e4..edab09101c50b6a02ce592d31e22ec6e530f6244 100644 (file)
@@ -90,6 +90,10 @@ static void master_sigchld(int sig, int code, struct sigcontext * scp)
     master_gotsigchld = sig;
     if (scp != NULL && scp->sc_syscall == SYS_select) {
        scp->sc_syscall_action = SIG_RETURN;
+#ifndef SA_RESTART
+    } else if (scp != NULL) {
+       scp->sc_syscall_action = SIG_RESTART;
+#endif
     }
 }
 
index a7bfe6e758664b8bc0186a7b6d3be2e5f22e5eb2..a1b5215c24c5caf9237033f89ab35e5b691478fb 100644 (file)
@@ -79,7 +79,7 @@ static void master_unthrottle(MASTER_SERV *serv);
 
 /* master_unthrottle_wrapper - in case (char *) != (struct *) */
 
-static void master_unthrottle_wrapper(char *ptr)
+static void master_unthrottle_wrapper(int unused_event, char *ptr)
 {
     MASTER_SERV *serv = (MASTER_SERV *) ptr;
 
index 6689794b5c60d4fad876666d20c3b226181f60b2..669147a95c0850f7ca4ed351e4afe10a9b7e3a96 100644 (file)
@@ -46,6 +46,7 @@
   * Tunable parameters.
   */
 int     var_proc_limit;
+int     var_throttle_time;
 
 /* master_vars_init - initialize from global Postfix configuration file */
 
@@ -54,6 +55,7 @@ void    master_vars_init(void)
     char   *path;
     static CONFIG_INT_TABLE int_table[] = {
        VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
+       VAR_THROTTLE_TIME, DEF_THROTTLE_TIME, &var_throttle_time, 1, 0,
        0,
     };
 
@@ -63,4 +65,3 @@ void    master_vars_init(void)
     fset_master_ent(path);
     myfree(path);
 }
-
index 4e3a1a99436474e6b0573c8173be8464bc4c1a75..7070d84d6b5fca022fe9806ea18eddcec8b6ee3c 100644 (file)
@@ -70,7 +70,7 @@
 
 /* master_wakeup_timer_event - wakeup event handler */
 
-static void master_wakeup_timer_event(char *context)
+static void master_wakeup_timer_event(int unused_event, char *context)
 {
     char   *myname = "master_wakeup_timer_event";
     MASTER_SERV *serv = (MASTER_SERV *) context;
@@ -129,7 +129,7 @@ void    master_wakeup_init(MASTER_SERV *serv)
     if (msg_verbose)
        msg_info("%s: service %s time %d",
                 myname, serv->name, serv->wakeup_time);
-    master_wakeup_timer_event((char *) serv);
+    master_wakeup_timer_event(0, (char *) serv);
 }
 
 /* master_wakeup_cleanup - cancel wakeup timer */
index 3cf0a013f4452a1021dfeb024b71fb5f164046e7..a3d04b48ea18307aecf9fc81cd74ce11f258f6b7 100644 (file)
@@ -71,6 +71,9 @@
 /*     or whenever nothing has happened for a specified amount of time.
 /*     The result value of the function specifies how long to wait until
 /*     the next event. Specify -1 to wait for "as long as it takes".
+/* .IP "MAIL_SERVER_EXIT (void *(void))"
+/*     A pointer to function that is executed immediately before normal
+/*     process termination.
 /* .PP
 /*     multi_server_disconnect() should be called by the application
 /*     when a client disconnects.
 #include <iostuff.h>
 #include <stringops.h>
 #include <sane_accept.h>
+#ifndef NO_SELECT_COLLISION
+#include <myflock.h>
+#include <safe_open.h>
+#endif
 
 /* Global library. */
 
@@ -157,6 +164,21 @@ static int use_count;
 static void (*multi_server_service) (VSTREAM *, char *, char **);
 static char *multi_server_name;
 static char **multi_server_argv;
+static void (*multi_server_onexit) (void);
+
+#ifndef NO_SELECT_COLLISION
+static VSTREAM *multi_server_lock;
+
+#endif
+
+/* multi_server_exit - normal termination */
+
+static NORETURN multi_server_exit(void)
+{
+    if (multi_server_onexit)
+       multi_server_onexit();
+    exit(0);
+}
 
 /* multi_server_abort - terminate after abnormal master exit */
 
@@ -164,16 +186,16 @@ static void multi_server_abort(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("master disconnect -- exiting");
-    exit(0);
+    multi_server_exit();
 }
 
 /* multi_server_timeout - idle time exceeded */
 
-static void multi_server_timeout(char *unused_context)
+static void multi_server_timeout(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("idle timeout -- exiting");
-    exit(0);
+    multi_server_exit();
 }
 
 /* multi_server_disconnect - terminate client session */
@@ -194,6 +216,12 @@ static void multi_server_execute(int unused_event, char *context)
 {
     VSTREAM *stream = (VSTREAM *) context;
 
+#ifndef NO_SELECT_COLLISION
+    if (multi_server_lock != 0
+       && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0)
+       msg_fatal("select unlock: %m");
+#endif
+
     /*
      * Do not bother the application when the client disconnected.
      */
@@ -215,6 +243,12 @@ static void multi_server_accept(int unused_event, char *context)
     int     fd;
     VSTREAM *stream;
 
+#ifndef NO_SELECT_COLLISION
+    if (multi_server_lock != 0
+       && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0)
+       msg_fatal("select unlock: %m");
+#endif
+
     /*
      * Be prepared for accept() to fail because some other process already
      * got the connection (the number of processes competing for clients is
@@ -262,6 +296,13 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
     int     key;
     char   *transport = 0;
 
+#ifndef NO_SELECT_COLLISION
+    char   *lock_path;
+    VSTRING *why;
+
+#endif
+    int     alone = 0;
+
     /*
      * Process environment options as early as we can.
      */
@@ -315,6 +356,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
        case MAIL_SERVER_LOOP:
            loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
            break;
+       case MAIL_SERVER_EXIT:
+           multi_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
+           break;
        default:
            msg_panic("%s: unknown argument type: %d", myname, key);
        }
@@ -326,7 +370,7 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
      * stderr, because no-one is going to see them.
      */
     opterr = 0;
-    while ((c = GETOPT(argc, argv, "cDi:m:n:s:St:uv")) > 0) {
+    while ((c = GETOPT(argc, argv, "cDi:lm:n:s:St:uv")) > 0) {
        switch (c) {
        case 'c':
            root_dir = var_queue_dir;
@@ -338,6 +382,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
            if ((var_idle_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_idle time: %s", optarg);
            break;
+       case 'l':
+           alone = 1;
+           break;
        case 'm':
            if ((var_use_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_use: %s", optarg);
@@ -375,12 +422,43 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
        msg_fatal("do not run this command by hand");
     }
 
+    /*
+     * Can options be required?
+     */
+    if (stream == 0) {
+       if (transport == 0)
+           msg_fatal("no transport type specified");
+       if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
+           && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
+           msg_fatal("unsupported transport type: %s", transport);
+    }
+
     /*
      * Optionally start the debugger on ourself.
      */
     if (debug_me)
        debug_process();
 
+    /*
+     * Traditionally, BSD select() can't handle multiple processes selecting
+     * on the same socket, and wakes up every process in select(). See TCP/IP
+     * Illustrated volume 2 page 532. We avoid select() collisions with an
+     * external lock file.
+     */
+#ifndef NO_SELECT_COLLISION
+    if (stream == 0 && !alone) {
+       lock_path = concatenate(DEF_PID_DIR, "/", transport,
+                               ".", service_name, (char *) 0);
+       why = vstring_alloc(1);
+       if ((multi_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
+                                          -1, -1, why)) == 0)
+           msg_fatal("%s", vstring_str(why));
+       close_on_exec(vstream_fileno(multi_server_lock), CLOSE_ON_EXEC);
+       myfree(lock_path);
+       vstring_free(why);
+    }
+#endif
+
     /*
      * Run pre-jail initialization.
      */
@@ -413,18 +491,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
                        VSTREAM_CTL_END);
        service(stream, service_name, argv + optind);
        vstream_fflush(stream);
-       exit(0);
+       multi_server_exit();
     }
 
-    /*
-     * Can options be required?
-     */
-    if (transport == 0)
-       msg_fatal("no transport type specified");
-    if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
-       && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
-       msg_fatal("unsupported transport type: %s", transport);
-
     /*
      * Running as a semi-resident server. Service connection requests.
      * Terminate when we have serviced a sufficient number of clients, when
@@ -444,7 +513,12 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
     close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
     while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
        delay = loop ? loop() : -1;
+#ifndef NO_SELECT_COLLISION
+       if (multi_server_lock != 0
+       && myflock(vstream_fileno(multi_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+           msg_fatal("select lock: %m");
+#endif
        event_loop(delay);
     }
-    exit(0);
+    multi_server_exit();
 }
index 750176fac361a2d11059de67ea5718cfb16272c0..4976ae02cf1b3f38f096f4fb6f4a63f36ad47a40 100644 (file)
 /*     or whenever nothing has happened for a specified amount of time.
 /*     The result value of the function specifies how long to wait until
 /*     the next event. Specify -1 to wait for "as long as it takes".
+/* .IP "MAIL_SERVER_EXIT (void *(void))"
+/*     A pointer to function that is executed immediately before normal
+/*     process termination.
 /* .PP
 /*     The var_use_limit variable limits the number of clients that
 /*     a server can service before it commits suicide.
 /*     This value is taken from the global \fBmain.cf\fR configuration
-/*     file. Setting \fBvar_use_limit\fR to zero disables the client limit.
+/*     file. Setting \fBvar_idle_limit\fR to zero disables the client limit.
 /*
 /*     The var_idle_limit variable limits the time that a service
 /*     receives no client connection requests before it commits suicide.
 #include <iostuff.h>
 #include <stringops.h>
 #include <sane_accept.h>
+#ifndef NO_SELECT_COLLISION
+#include <myflock.h>
+#include <safe_open.h>
+#endif
 
 /* Global library. */
 
@@ -147,6 +154,21 @@ static int use_count;
 static void (*single_server_service) (VSTREAM *, char *, char **);
 static char *single_server_name;
 static char **single_server_argv;
+static void (*single_server_onexit) (void);
+
+#ifndef NO_SELECT_COLLISION
+static VSTREAM *single_server_lock;
+
+#endif
+
+/* single_server_exit - normal termination */
+
+static NORETURN single_server_exit(void)
+{
+    if (single_server_onexit)
+       single_server_onexit();
+    exit(0);
+}
 
 /* single_server_abort - terminate after abnormal master exit */
 
@@ -154,16 +176,16 @@ static void single_server_abort(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("master disconnect -- exiting");
-    exit(0);
+    single_server_exit();
 }
 
 /* single_server_timeout - idle time exceeded */
 
-static void single_server_timeout(char *unused_context)
+static void single_server_timeout(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("idle timeout -- exiting");
-    exit(0);
+    single_server_exit();
 }
 
 /* single_server_accept - accept client connection request */
@@ -175,6 +197,12 @@ static void single_server_accept(int unused_event, char *context)
     int     time_left = -1;
     int     fd;
 
+#ifndef NO_SELECT_COLLISION
+    if (single_server_lock != 0
+       && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0)
+       msg_fatal("select unlock: %m");
+#endif
+
     /*
      * Be prepared for accept() to fail because some other process already
      * got the connection. We use select() + accept(), instead of simply
@@ -238,6 +266,13 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
     int     key;
     char   *transport = 0;
 
+#ifndef NO_SELECT_COLLISION
+    char   *lock_path;
+    VSTRING *why;
+
+#endif
+    int     alone = 0;
+
     /*
      * Process environment options as early as we can.
      */
@@ -291,6 +326,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
        case MAIL_SERVER_LOOP:
            loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
            break;
+       case MAIL_SERVER_EXIT:
+           single_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
+           break;
        default:
            msg_panic("%s: unknown argument type: %d", myname, key);
        }
@@ -302,7 +340,7 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
      * stderr, because no-one is going to see them.
      */
     opterr = 0;
-    while ((c = GETOPT(argc, argv, "cDi:m:n:s:St:uv")) > 0) {
+    while ((c = GETOPT(argc, argv, "cDi:lm:n:s:St:uv")) > 0) {
        switch (c) {
        case 'c':
            root_dir = var_queue_dir;
@@ -314,6 +352,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
            if ((var_idle_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_idle time: %s", optarg);
            break;
+       case 'l':
+           alone = 1;
+           break;
        case 'm':
            if ((var_use_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_use: %s", optarg);
@@ -351,12 +392,43 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
        msg_fatal("do not run this command by hand");
     }
 
+    /*
+     * Can options be required?
+     */
+    if (stream == 0) {
+       if (transport == 0)
+           msg_fatal("no transport type specified");
+       if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
+           && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
+           msg_fatal("unsupported transport type: %s", transport);
+    }
+
     /*
      * Optionally start the debugger on ourself.
      */
     if (debug_me)
        debug_process();
 
+    /*
+     * Traditionally, BSD select() can't handle multiple processes selecting
+     * on the same socket, and wakes up every process in select(). See TCP/IP
+     * Illustrated volume 2 page 532. We avoid select() collisions with an
+     * external lock file.
+     */
+#ifndef NO_SELECT_COLLISION
+    if (stream == 0 && !alone) {
+       lock_path = concatenate(DEF_PID_DIR, "/", transport,
+                               ".", service_name, (char *) 0);
+       why = vstring_alloc(1);
+       if ((single_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
+                                           -1, -1, why)) == 0)
+           msg_fatal("%s", vstring_str(why));
+       close_on_exec(vstream_fileno(single_server_lock), CLOSE_ON_EXEC);
+       myfree(lock_path);
+       vstring_free(why);
+    }
+#endif
+
     /*
      * Run pre-jail initialization.
      */
@@ -389,18 +461,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
                        VSTREAM_CTL_END);
        service(stream, service_name, argv + optind);
        vstream_fflush(stream);
-       exit(0);
+       single_server_exit();
     }
 
-    /*
-     * Can options be required?
-     */
-    if (transport == 0)
-       msg_fatal("no transport type specified");
-    if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0
-       && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0)
-       msg_fatal("unsupported transport type: %s", transport);
-
     /*
      * Running as a semi-resident server. Service connection requests.
      * Terminate when we have serviced a sufficient number of clients, when
@@ -420,7 +483,12 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
     close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
     while (var_use_limit == 0 || use_count < var_use_limit) {
        delay = loop ? loop() : -1;
+#ifndef NO_SELECT_COLLISION
+       if (single_server_lock != 0
+           && myflock(vstream_fileno(single_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+           msg_fatal("select lock: %m");
+#endif
        event_loop(delay);
     }
-    exit(0);
+    single_server_exit();
 }
index 9338e0b4b59bdbe3ab180db9be0db228cfb047f3..651adac313bb133c1b427103f917f637a8921eaa 100644 (file)
@@ -73,6 +73,9 @@
 /*     or whenever nothing has happened for a specified amount of time.
 /*     The result value of the function specifies how long to wait until
 /*     the next event. Specify -1 to wait for "as long as it takes".
+/* .IP "MAIL_SERVER_EXIT (void *(void))"
+/*     A pointer to function that is executed immediately before normal
+/*     process termination.
 /* .PP
 /*     The var_use_limit variable limits the number of clients that
 /*     a server can service before it commits suicide.
 #include <iostuff.h>
 #include <stringops.h>
 #include <sane_accept.h>
+#ifndef NO_SELECT_COLLISION
+#include <myflock.h>
+#include <safe_open.h>
+#endif
 
 /* Global library. */
 
@@ -155,6 +162,34 @@ static TRIGGER_SERVER_FN trigger_server_service;
 static char *trigger_server_name;
 static char **trigger_server_argv;
 static void (*trigger_server_accept) (int, char *);
+static void (*trigger_server_onexit) (void);
+
+#ifndef NO_SELECT_COLLISION
+static VSTREAM *trigger_server_lock;
+
+#endif
+
+/* trigger_server_exit - normal termination */
+
+static NORETURN trigger_server_exit(void)
+{
+    if (trigger_server_onexit)
+       trigger_server_onexit();
+    exit(0);
+}
+
+/* trigger_server_watchdog - something got stuck */
+
+static NORETURN trigger_server_watchdog(int unused_sig)
+{
+
+    /*
+     * This runs as a signal handler. We should not do anything that could
+     * involve memory managent, but exiting without explanation would be
+     * worse.
+     */
+    msg_fatal("watchdog timer");
+}
 
 /* trigger_server_abort - terminate after abnormal master exit */
 
@@ -162,16 +197,16 @@ static void trigger_server_abort(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("master disconnect -- exiting");
-    exit(0);
+    trigger_server_exit();
 }
 
 /* trigger_server_timeout - idle time exceeded */
 
-static void trigger_server_timeout(char *unused_context)
+static void trigger_server_timeout(int unused_event, char *unused_context)
 {
     if (msg_verbose)
        msg_info("idle timeout -- exiting");
-    exit(0);
+    trigger_server_exit();
 }
 
 /* trigger_server_wakeup - wake up application */
@@ -203,12 +238,19 @@ static void trigger_server_accept_fifo(int unused_event, char *context)
     char   *myname = "trigger_server_accept_fifo";
     int     listen_fd = (int) context;
 
+#ifndef NO_SELECT_COLLISION
+    if (trigger_server_lock != 0
+       && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0)
+       msg_fatal("select unlock: %m");
+#endif
+
     if (msg_verbose)
        msg_info("%s: trigger arrived", myname);
 
     /*
      * Some buggy systems cause Postfix to lock up.
      */
+    signal(SIGALRM, trigger_server_watchdog);
     alarm(1000);
 
     /*
@@ -227,6 +269,12 @@ static void trigger_server_accept_socket(int unused_event, char *context)
     int     time_left = 0;
     int     fd;
 
+#ifndef NO_SELECT_COLLISION
+    if (trigger_server_lock != 0
+       && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0)
+       msg_fatal("select unlock: %m");
+#endif
+
     if (msg_verbose)
        msg_info("%s: trigger arrived", myname);
 
@@ -282,6 +330,13 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
     int     len;
     char   *transport = 0;
 
+#ifndef NO_SELECT_COLLISION
+    char   *lock_path;
+    VSTRING *why;
+
+#endif
+    int     alone = 0;
+
     /*
      * Process environment options as early as we can.
      */
@@ -335,6 +390,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
        case MAIL_SERVER_LOOP:
            loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
            break;
+       case MAIL_SERVER_EXIT:
+           trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
+           break;
        default:
            msg_panic("%s: unknown argument type: %d", myname, key);
        }
@@ -346,7 +404,7 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
      * stderr, because no-one is going to see them.
      */
     opterr = 0;
-    while ((c = GETOPT(argc, argv, "cDi:m:n:s:St:uv")) > 0) {
+    while ((c = GETOPT(argc, argv, "cDi:lm:n:s:St:uv")) > 0) {
        switch (c) {
        case 'c':
            root_dir = var_queue_dir;
@@ -358,6 +416,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
            if ((var_idle_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_idle time: %s", optarg);
            break;
+       case 'l':
+           alone = 1;
+           break;
        case 'm':
            if ((var_use_limit = atoi(optarg)) <= 0)
                msg_fatal("invalid max_use: %s", optarg);
@@ -395,12 +456,59 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
        msg_fatal("do not run this command by hand");
     }
 
+    /*
+     * Can options be required?
+     * 
+     * XXX Initially this code was implemented with UNIX-domain sockets, but
+     * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
+     * client disconnects before the server has accepted the connection.
+     * Symptom: the server accept() fails with EPIPE or EPROTO, but the
+     * socket stays readable, so that the program goes into a wasteful loop.
+     * 
+     * The initial fix was to use FIFOs, but those turn out to have their own
+     * problems, witness the workarounds in the fifo_listen() routine.
+     * Therefore we support both FIFOs and UNIX-domain sockets, so that the
+     * user can choose whatever works best.
+     */
+    if (stream == 0) {
+       if (transport == 0)
+           msg_fatal("no transport type specified");
+       if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
+           trigger_server_accept = trigger_server_accept_socket;
+       if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
+           trigger_server_accept = trigger_server_accept_socket;
+       else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
+           trigger_server_accept = trigger_server_accept_fifo;
+       else
+           msg_fatal("unsupported transport type: %s", transport);
+    }
+
     /*
      * Optionally start the debugger on ourself.
      */
     if (debug_me)
        debug_process();
 
+    /*
+     * Traditionally, BSD select() can't handle multiple processes selecting
+     * on the same socket, and wakes up every process in select(). See TCP/IP
+     * Illustrated volume 2 page 532. We avoid select() collisions with an
+     * external lock file.
+     */
+#ifndef NO_SELECT_COLLISION
+    if (stream == 0 && !alone) {
+       lock_path = concatenate(DEF_PID_DIR, "/", transport,
+                               ".", service_name, (char *) 0);
+       why = vstring_alloc(1);
+       if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
+                                            -1, -1, why)) == 0)
+           msg_fatal("%s", vstring_str(why));
+       close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
+       myfree(lock_path);
+       vstring_free(why);
+    }
+#endif
+
     /*
      * Run pre-jail initialization.
      */
@@ -430,34 +538,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
            msg_fatal("read: %m");
        service(buf, len, service_name, argv + optind);
        vstream_fflush(stream);
-       exit(0);
+       trigger_server_exit();
     }
 
-    /*
-     * Can options be required?
-     * 
-     * XXX Initially this code was implemented with UNIX-domain sockets, but
-     * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
-     * client disconnects before the server has accepted the connection.
-     * Symptom: the server accept() fails with EPIPE or EPROTO, but the
-     * socket stays readable, so that the program goes into a wasteful loop.
-     * 
-     * The initial fix was to use FIFOs, but those turn out to have their own
-     * problems, witness the workarounds in the fifo_listen() routine.
-     * Therefore we support both FIFOs and UNIX-domain sockets, so that the
-     * user can choose whatever works best.
-     */
-    if (transport == 0)
-       msg_fatal("no transport type specified");
-    if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
-       trigger_server_accept = trigger_server_accept_socket;
-    if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
-       trigger_server_accept = trigger_server_accept_socket;
-    else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
-       trigger_server_accept = trigger_server_accept_fifo;
-    else
-       msg_fatal("unsupported transport type: %s", transport);
-
     /*
      * Running as a semi-resident server. Service connection requests.
      * Terminate when we have serviced a sufficient number of clients, when
@@ -477,7 +560,12 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
     close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
     while (var_use_limit == 0 || use_count < var_use_limit) {
        delay = loop ? loop() : -1;
+#ifndef NO_SELECT_COLLISION
+       if (trigger_server_lock != 0
+           && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+           msg_fatal("select lock: %m");
+#endif
        event_loop(delay);
     }
-    exit(0);
+    trigger_server_exit();
 }
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 1edbf8c3b4f74a16994d9d8dd1a5f5ccca48e3d6..fcb0c1c7bc6e37cb23ad2a3f20cd215603ff3892 100644 (file)
@@ -53,6 +53,7 @@ depend: $(MAKES)
        @make -f Makefile.in Makefile
 
 # do not edit below this line - it is generated by 'make depend'
+cleanup_extra.o: cleanup_extra.c
 pickup.o: pickup.c
 pickup.o: ../include/sys_defs.h
 pickup.o: ../include/msg.h
index ed3aead028f63702c826f828c60d68420ceb789d..7ef02cb0b2242836a53ad518d66b5fa5f96c03b0 100644 (file)
@@ -43,6 +43,8 @@
 /* .SH Miscellaneous
 /* .ad
 /* .fi
+/* .IP \fBalways_bcc\fR
+/*     Address to send a copy of each message that enters the system.
 /* .IP \fBmail_owner\fR
 /*      The process privileges used while not opening a \fBmaildrop\fR file.
 /* .IP \fBqueue_directory\fR
 
 /* Application-specific. */
 
+char   *var_always_bcc;
+
  /*
   * Structure to bundle a bunch of information about a queue file.
   */
@@ -231,12 +235,15 @@ static int pickup_copy(VSTREAM *qfile, VSTREAM *cleanup,
             (int) info->st.st_uid, info->sender);
     myfree(info->sender);
 
+    if (*var_always_bcc)
+       rec_fputs(cleanup, REC_TYPE_RCPT, var_always_bcc);
+
     /*
      * Message content segment. Send a dummy message length. Prepend a
      * Received: header to the message contents. For tracing purposes,
      * include the message file ownership, without revealing the login name.
      */
-    rec_fprintf(cleanup, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0);
+    rec_fputs(cleanup, REC_TYPE_MESG, "");
     rec_fprintf(cleanup, REC_TYPE_NORM, "Received: by %s (%s, from userid %d)",
                var_myhostname, var_mail_name, info->st.st_uid);
     rec_fprintf(cleanup, REC_TYPE_NORM, "\tid %s; %s", info->id,
@@ -402,12 +409,17 @@ static void drop_privileges(void)
 
 int     main(int argc, char **argv)
 {
+    static CONFIG_STR_TABLE str_table[] = {
+       VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
+       0,
+    };
 
     /*
      * Use the multi-threaded skeleton, because no-one else should be
      * monitoring our service socket while this process runs.
      */
     trigger_server_main(argc, argv, pickup_service,
+                       MAIL_SERVER_STR_TABLE, str_table,
                        MAIL_SERVER_POST_INIT, drop_privileges,
                        0);
 }
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 408b43f9a69f9a0245f3cd9a6d1bdbd24c529753..60c5e96a5413274a85294a7baff9b1f06671b6d7 100644 (file)
@@ -22,7 +22,7 @@
 /* .fi
 /*     The external command attributes are given in the \fBmaster.cf\fR
 /*     file at the end of a service definition.  The syntax is as follows:
-/* .IP "\fBflags=F>\fR (optional)"
+/* .IP "\fBflags=FR>\fR (optional)"
 /*     Optional message processing flags. By default, a message is
 /*     copied unchanged.
 /* .RS
 /*     the message content.
 /*     This is expected by, for example, \fBUUCP\fR software. The \fBF\fR
 /*     flag also causes an empty line to be appended to the message.
+/* .IP \fBR\fR
+/*     Prepend a \fBReturn-Path:\fR message header with the envelope sender
+/*     address.
 /* .IP \fB>\fR
-/*     Prepend \fB>\fR to lines starting with "\fBFrom \fR". This expected
+/*     Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
 /*     by, for example, \fBUUCP\fR software.
 /* .RE
 /* .IP "\fBuser\fR=\fIusername\fR (required)"
+/* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
 /*     The external command is executed with the rights of the
 /*     specified \fIusername\fR.  The software refuses to execute
 /*     commands with root privileges, or with the privileges of the
-/*     mail system owner.
+/*     mail system owner. If \fIgroupname\fR is specified, the
+/*     corresponding group ID is used instead of the group ID of
+/*     of \fIusername\fR.
 /* .IP "\fBargv\fR=\fIcommand\fR... (required)"
 /*     The command to be executed. This must be specified as the
 /*     last command attribute.
 #include <stdlib.h>
 #include <string.h>
 #include <pwd.h>
+#include <grp.h>
 #include <fcntl.h>
 
 #ifdef STRCASECMP_IN_STRINGS_H
@@ -236,7 +243,6 @@ typedef struct {
   * Structure for command-line parameters.
   */
 typedef struct {
-    char   *user;                      /* user name */
     char  **command;                   /* argument vector */
     uid_t   uid;                       /* command privileges */
     gid_t   gid;                       /* command privileges */
@@ -310,9 +316,9 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list)
 
                /*
                 * This argument contains $user. Extract the plain user name.
-                * Either anything to the left of the extension delimiter
-                * or, in absence of the latter, anything to the left of
-                * the rightmost @.
+                * Either anything to the left of the extension delimiter or,
+                * in absence of the latter, anything to the left of the
+                * rightmost @.
                 * 
                 * Beware: if the user name is blank (e.g. +user@host), the
                 * argument is suppressed. This is necessary to allow for
@@ -397,12 +403,16 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
 {
     char   *myname = "get_service_attr";
     struct passwd *pwd;
+    struct group *grp;
+    char   *user;                      /* user name */
+    char   *group;                     /* group name */
     char   *cp;
 
     /*
      * Initialize.
      */
-    attr->user = 0;
+    user = 0;
+    group = 0;
     attr->command = 0;
     attr->flags = 0;
 
@@ -423,6 +433,9 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
                case '>':
                    attr->flags |= MAIL_COPY_QUOTE;
                    break;
+               case 'R':
+                   attr->flags |= MAIL_COPY_RETURN_PATH;
+                   break;
                default:
                    msg_fatal("unknown flag: %c (ignored)", *cp);
                    break;
@@ -431,14 +444,23 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
        }
 
        /*
-        * user=username
+        * user=username[:groupname]
         */
        else if (strncasecmp("user=", *argv, sizeof("user=") - 1) == 0) {
-           attr->user = *argv + sizeof("user=") - 1;
-           if ((pwd = getpwnam(attr->user)) == 0)
-               msg_fatal("%s: unknown username: %s", myname, attr->user);
+           user = *argv + sizeof("user=") - 1;
+           if ((group = split_at(user, ':')) != 0)     /* XXX clobbers argv */
+               if (*group == 0)
+                   group = 0;
+           if ((pwd = getpwnam(user)) == 0)
+               msg_fatal("%s: unknown username: %s", myname, user);
            attr->uid = pwd->pw_uid;
-           attr->gid = pwd->pw_gid;
+           if (group != 0) {
+               if ((grp = getgrnam(group)) == 0)
+                   msg_fatal("%s: unknown group: %s", myname, group);
+               attr->gid = grp->gr_gid;
+           } else {
+               attr->gid = pwd->pw_gid;
+           }
        }
 
        /*
@@ -460,7 +482,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
     /*
      * Sanity checks. Verify that every member has an acceptable value.
      */
-    if (attr->user == 0)
+    if (user == 0)
        msg_fatal("missing user= attribute");
     if (attr->command == 0)
        msg_fatal("missing argv= attribute");
@@ -575,7 +597,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
        msg_fatal("empty nexthop hostname");
     if (rcpt_list->len <= 0)
        msg_fatal("recipient count: %d", rcpt_list->len);
-    if (attr.user == 0) {
+    if (attr.command == 0) {
        get_service_params(&conf, service);
        get_service_attr(&attr, argv);
     }
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index efa74f5a51069d7009dc90f4e057f9232aeefcd7..0f77e54212b7f307e70735ee5498e6ba34fce9f5 100644 (file)
@@ -101,6 +101,10 @@ static void postcat(VSTREAM *fp, VSTRING *buffer)
            time = atol(STR(buffer));
            vstream_printf("arrival_time: %s", asctime(localtime(&time)));
            break;
+       case REC_TYPE_WARN:
+           time = atol(STR(buffer));
+           vstream_printf("defer_warn_time: %s", asctime(localtime(&time)));
+           break;
        case REC_TYPE_CONT:
            vstream_printf("%s", STR(buffer));
            break;
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index f532f954dc08c539070bf48993f27d75404530d6..4c7043bffe9fe3b996d3da1bf13c5736b67801ac 100644 (file)
@@ -30,7 +30,7 @@ update: ../bin/$(PROG)
 ../bin/$(PROG): $(PROG)
        cp $(PROG) ../bin
 
-$(MAKES):
+$(MAKES): $(INC_DIR)/mail_params.h
        sh extract.sh ../*/*.c
 
 printfck: $(OBJS) $(PROG)
index a38c895a702e28eb525bab6145ddc23576d9cc0b..cbf755dc76d77dc3f4ecd8d28a3312b25b4c5193 100644 (file)
@@ -5,14 +5,19 @@
 /*     Postfix configuration utility
 /* SYNOPSIS
 /* .fi
-/*     \fBpostconf\fR [\fB-d\fR] [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
+/*     \fBpostconf\fR [\fB-d\fR] [\fB-h\fR] [\fB-n\fR] [\fB-v\fR]
+/*             [\fIparameter ...\fR]
 /* DESCRIPTION
 /*     The \fBpostconf\fR command prints the actual value of
-/*     \fIparameter\fR (all known parameters by default).
+/*     \fIparameter\fR (all known parameters by default), one
+/*     parameter per line.
 /*
 /*     Options:
 /* .IP \fB-d\fR
 /*     Print default parameter settings instead of actual settings.
+/* .IP \fB-h\fR
+/*     Show parameter values only, not the \fIname =\fR information
+/*     that normally precedes the value.
 /* .IP \fB-n\fR
 /*     Print non-default parameter settings only.
 /* .IP \fB-v\fR
 #include <strings.h>
 #endif
 
+#ifdef USE_PATHS_H
+#include <paths.h>
+#endif
+
 /* Utility library. */
 
 #include <msg.h>
@@ -71,6 +80,7 @@
   */
 #define SHOW_NONDEF    (1<<0)          /* show non-default settings */
 #define SHOW_DEFS      (1<<1)          /* show default setting */
+#define SHOW_NAME      (1<<2)          /* show parameter name */
 
  /*
   * Lookup table for in-core parameter info.
@@ -225,6 +235,28 @@ static void hash_parameters(void)
        htable_enter(param_table, csft->name, (char *) csft);
 }
 
+/* show_strval - show string-valued parameter */
+
+static void show_strval(int mode, const char *name, const char *value)
+{
+    if (mode & SHOW_NAME) {
+       vstream_printf("%s = %s\n", name, value);
+    } else {
+       vstream_printf("%s\n", value);
+    }
+}
+
+/* show_intval - show integer-valued parameter */
+
+static void show_intval(int mode, const char *name, int value)
+{
+    if (mode & SHOW_NAME) {
+       vstream_printf("%s = %d\n", name, value);
+    } else {
+       vstream_printf("%d\n", value);
+    }
+}
+
 /* print_bool - print boolean parameter */
 
 static void print_bool(int mode, CONFIG_BOOL_TABLE *cbt)
@@ -232,18 +264,18 @@ static void print_bool(int mode, CONFIG_BOOL_TABLE *cbt)
     const char *value;
 
     if (mode & SHOW_DEFS) {
-       vstream_printf("%s = %s\n", cbt->name, cbt->defval ? "yes" : "no");
+       show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
     } else {
        value = dict_lookup(CONFIG_DICT, cbt->name);
        if ((mode & SHOW_NONDEF) == 0) {
            if (value == 0) {
-               vstream_printf("%s = %s\n", cbt->name, cbt->defval ? "yes" : "no");
+               show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
            } else {
-               vstream_printf("%s = %s\n", cbt->name, value);
+               show_strval(mode, cbt->name, value);
            }
        } else {
            if (value != 0)
-               vstream_printf("%s = %s\n", cbt->name, value);
+               show_strval(mode, cbt->name, value);
        }
     }
 }
@@ -255,18 +287,18 @@ static void print_int(int mode, CONFIG_INT_TABLE *cit)
     const char *value;
 
     if (mode & SHOW_DEFS) {
-       vstream_printf("%s = %d\n", cit->name, cit->defval);
+       show_intval(mode, cit->name, cit->defval);
     } else {
        value = dict_lookup(CONFIG_DICT, cit->name);
        if ((mode & SHOW_NONDEF) == 0) {
            if (value == 0) {
-               vstream_printf("%s = %d\n", cit->name, cit->defval);
+               show_intval(mode, cit->name, cit->defval);
            } else {
-               vstream_printf("%s = %s\n", cit->name, value);
+               show_strval(mode, cit->name, value);
            }
        } else {
            if (value != 0)
-               vstream_printf("%s = %s\n", cit->name, value);
+               show_strval(mode, cit->name, value);
        }
     }
 }
@@ -278,18 +310,18 @@ static void print_str(int mode, CONFIG_STR_TABLE *cst)
     const char *value;
 
     if (mode & SHOW_DEFS) {
-       vstream_printf("%s = %s\n", cst->name, cst->defval);
+       show_strval(mode, cst->name, cst->defval);
     } else {
        value = dict_lookup(CONFIG_DICT, cst->name);
        if ((mode & SHOW_NONDEF) == 0) {
            if (value == 0) {
-               vstream_printf("%s = %s\n", cst->name, cst->defval);
+               show_strval(mode, cst->name, cst->defval);
            } else {
-               vstream_printf("%s = %s\n", cst->name, value);
+               show_strval(mode, cst->name, value);
            }
        } else {
            if (value != 0)
-               vstream_printf("%s = %s\n", cst->name, value);
+               show_strval(mode, cst->name, value);
        }
     }
 }
@@ -301,18 +333,18 @@ static void print_str_fn(int mode, CONFIG_STR_FN_TABLE *csft)
     const char *value;
 
     if (mode & SHOW_DEFS) {
-       vstream_printf("%s = %s\n", csft->name, csft->defval());
+       show_strval(mode, csft->name, csft->defval());
     } else {
        value = dict_lookup(CONFIG_DICT, csft->name);
        if ((mode & SHOW_NONDEF) == 0) {
            if (value == 0) {
-               vstream_printf("%s = %s\n", csft->name, csft->defval());
+               show_strval(mode, csft->name, csft->defval());
            } else {
-               vstream_printf("%s = %s\n", csft->name, value);
+               show_strval(mode, csft->name, value);
            }
        } else {
            if (value != 0)
-               vstream_printf("%s = %s\n", csft->name, value);
+               show_strval(mode, csft->name, value);
        }
     }
 }
@@ -324,18 +356,18 @@ static void print_str_fn_2(int mode, CONFIG_STR_FN_TABLE *csft)
     const char *value;
 
     if (mode & SHOW_DEFS) {
-       vstream_printf("%s = %s\n", csft->name, csft->defval());
+       show_strval(mode, csft->name, csft->defval());
     } else {
        value = dict_lookup(CONFIG_DICT, csft->name);
        if ((mode & SHOW_NONDEF) == 0) {
            if (value == 0) {
-               vstream_printf("%s = %s\n", csft->name, csft->defval());
+               show_strval(mode, csft->name, csft->defval());
            } else {
-               vstream_printf("%s = %s\n", csft->name, value);
+               show_strval(mode, csft->name, value);
            }
        } else {
            if (value != 0)
-               vstream_printf("%s = %s\n", csft->name, value);
+               show_strval(mode, csft->name, value);
        }
     }
 }
@@ -412,7 +444,7 @@ static void show_parameters(int mode, char **names)
 int     main(int argc, char **argv)
 {
     int     ch;
-    int     mode = 0;
+    int     mode = SHOW_NAME;
     int     fd;
     struct stat st;
 
@@ -432,13 +464,16 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "dnv")) > 0) {
+    while ((ch = GETOPT(argc, argv, "dhnv")) > 0) {
        switch (ch) {
        case 'd':
            if (mode & SHOW_NONDEF)
                msg_fatal("specify one of -d and -n");
            mode |= SHOW_DEFS;
            break;
+       case 'h':
+           mode &= ~SHOW_NAME;
+           break;
        case 'n':
            if (mode & SHOW_DEFS)
                msg_fatal("specify one of -d and -n");
@@ -448,7 +483,7 @@ int     main(int argc, char **argv)
            msg_verbose++;
            break;
        default:
-           msg_fatal("usage: %s [-d (show default)] [-n (show non-default)] [-v] name...", argv[0]);
+           msg_fatal("usage: %s [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]);
        }
     }
 
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 4ff41f77b7705ff672ac80af478c219a065ea243..d2267db61aa1d555b87bb9e49d23987890b1b391 100644 (file)
@@ -14,7 +14,7 @@
 /*
 /*     The \fBpostdrop\fR command is automatically invoked by the
 /*     \fBsendmail\fR(1) mail posting agent when the \fBmaildrop\fR
-/*     queue directory is not writable.
+/*     queue directory is not world-writable.
 /*
 /*     Options:
 /* .IP \fB-v\fR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
diff --git a/postfix/postsuper/.indent.pro b/postfix/postsuper/.indent.pro
new file mode 100644 (file)
index 0000000..b38eded
--- /dev/null
@@ -0,0 +1,98 @@
+-TALIAS_TOKEN
+-TARGV
+-TBH_TABLE
+-TBINHASH
+-TBINHASH_INFO
+-TBOUNCE_STAT
+-TCLEANUP_STATE
+-TCLIENT_LIST
+-TCLNT_STREAM
+-TCONFIG_BOOL_FN_TABLE
+-TCONFIG_BOOL_TABLE
+-TCONFIG_INT_FN_TABLE
+-TCONFIG_INT_TABLE
+-TCONFIG_STR_FN_TABLE
+-TCONFIG_STR_TABLE
+-TDELIVER_ATTR
+-TDELIVER_REQUEST
+-TDICT
+-TDICT_DB
+-TDICT_DBM
+-TDICT_ENV
+-TDICT_HT
+-TDICT_LDAP
+-TDICT_NI
+-TDICT_NIS
+-TDICT_NISPLUS
+-TDICT_NODE
+-TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
+-TDNS_FIXED
+-TDNS_REPLY
+-TDNS_RR
+-TDOMAIN_LIST
+-TEXPAND_ATTR
+-TFILE
+-TFORWARD_INFO
+-THEADER_OPTS
+-THTABLE
+-THTABLE_INFO
+-TINET_ADDR_LIST
+-TINT_TABLE
+-TLOCAL_STATE
+-TMAC_HEAD
+-TMAC_PARSE
+-TMAIL_PRINT
+-TMAIL_SCAN
+-TMAPS
+-TMASTER_PROC
+-TMASTER_SERV
+-TMASTER_STATUS
+-TMBLOCK
+-TMKMAP
+-TMKMAP_OPEN_INFO
+-TMULTI_SERVER
+-TMVECT
+-TNAMADR_LIST
+-TNAME_MASK
+-TPEER_NAME
+-TPICKUP_INFO
+-TPIPE_ATTR
+-TPIPE_PARAMS
+-TQMGR_ENTRY
+-TQMGR_MESSAGE
+-TQMGR_QUEUE
+-TQMGR_RCPT_LIST
+-TQMGR_RECIPIENT
+-TQMGR_SCAN
+-TQMGR_TRANSPORT
+-TRECIPIENT
+-TRECIPIENT_LIST
+-TREC_TYPE_NAME
+-TRESOLVE_REPLY
+-TRESPONSE
+-TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
+-TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
+-TSMTPD_STATE
+-TSMTPD_TOKEN
+-TSMTP_ADDR
+-TSMTP_CMD
+-TSMTP_RESP
+-TSMTP_SESSION
+-TSMTP_STATE
+-TSOCKADDR_SIZE
+-TSTRING_TABLE
+-TSYS_EXITS_TABLE
+-TTOK822
+-TTRIGGER_SERVER
+-TUSER_ATTR
+-TVBUF
+-TVSTREAM
+-TVSTRING
+-TWAIT_STATUS_T
diff --git a/postfix/postsuper/.printfck b/postfix/postsuper/.printfck
new file mode 100644 (file)
index 0000000..9ed900c
--- /dev/null
@@ -0,0 +1,24 @@
+been_here_xt   2       0
+bounce_append  5       0
+cleanup_out_format     1       0
+defer_append   5       0
+mail_command   1       0
+mail_print     1       0
+msg_error      0       0
+msg_fatal      0       0
+msg_info       0       0
+msg_panic      0       0
+msg_warn       0       0
+opened 3       0
+qmgr_message_bounce    2       0
+rec_fprintf    2       0
+sent   4       0
+smtp_cmd       1       0
+smtp_mesg_fail 2       0
+smtp_printf    1       0
+smtp_rcpt_fail 3       0
+smtp_site_fail 2       0
+udp_syslog     1       0
+vstream_fprintf        1       0
+vstream_printf 0       0
+vstring_sprintf        1       0
diff --git a/postfix/postsuper/Makefile.in b/postfix/postsuper/Makefile.in
new file mode 100644 (file)
index 0000000..c91df1d
--- /dev/null
@@ -0,0 +1,72 @@
+SHELL  = /bin/sh
+SRCS   = postsuper.c 
+OBJS   = postsuper.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   = postsuper
+INC_DIR        = ../include
+LIBS   = ../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) sh ../makedefs; cat $?) >$@
+
+test:  $(TESTPROG)
+
+update: ../bin/$(PROG)
+
+../bin/$(PROG): $(PROG)
+       cp $(PROG) ../bin
+
+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
+       @make -f Makefile.in Makefile
+
+# do not edit below this line - it is generated by 'make depend'
+postsuper.o: postsuper.c
+postsuper.o: ../include/sys_defs.h
+postsuper.o: ../include/mymalloc.h
+postsuper.o: ../include/msg.h
+postsuper.o: ../include/msg_syslog.h
+postsuper.o: ../include/vstream.h
+postsuper.o: ../include/vbuf.h
+postsuper.o: ../include/msg_vstream.h
+postsuper.o: ../include/scan_dir.h
+postsuper.o: ../include/vstring.h
+postsuper.o: ../include/safe.h
+postsuper.o: ../include/set_ugid.h
+postsuper.o: ../include/argv.h
+postsuper.o: ../include/mail_task.h
+postsuper.o: ../include/config.h
+postsuper.o: ../include/mail_params.h
+postsuper.o: ../include/mail_queue.h
diff --git a/postfix/postsuper/postsuper.c b/postfix/postsuper/postsuper.c
new file mode 100644 (file)
index 0000000..5d575ce
--- /dev/null
@@ -0,0 +1,377 @@
+/*++
+/* NAME
+/*     postsuper 1
+/* SUMMARY
+/*     Postfix super intendent
+/* SYNOPSIS
+/* .fi
+/*     \fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
+/* DESCRIPTION
+/*     The \fBpostsuper\fR command does small maintenance jobs on the named
+/*     Postfix queue directories (default: all).
+/*     Directory names are relative to the Postfix top-level queue directory.
+/*
+/*     By default, \fBpostsuper\fR performs the operations requested with the
+/*     \fB-s\fR and \fB-p\fR command-line options.
+/*     \fBpostsuper\fR always tries to remove objects that are neither files
+/*     nor directories.  Use of this command is restricted to the super-user.
+/*
+/*     Options:
+/* .IP \fB-s\fR
+/*     Structure check.  Move queue files that are in the wrong place
+/*     in the file system hierarchy and remove subdirectories that are
+/*     no longer needed. File rearrangements are necessary after a change
+/*     in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR
+/*     configuration parameters. It is highly recommended to run this
+/*     check once before Postfix startup.
+/* .IP \fB-p\fR
+/*     Purge stale files (files that are left over after system or
+/*     software crashes).
+/* .IP \fB-v\fR
+/*     Enable verbose mode for debugging purposes. Multiple \fB-v\fR
+/*     options make the software increasingly verbose.
+/* DIAGNOSTICS
+/*     Problems are reported to the standard error stream and to
+/*     \fBsyslogd\fR.
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/*      See the Postfix \fBmain.cf\fR file for syntax details and for
+/*      default values.
+/* .IP \fBhash_queue_depth\fR
+/*     Number of subdirectory levels for hashed queues.
+/* .IP \fBhash_queue_names\fR
+/*     The names of queues that are organized into multiple levels of
+/*     subdirectories.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>                     /* remove() */
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <msg.h>
+#include <msg_syslog.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+#include <scan_dir.h>
+#include <vstring.h>
+#include <safe.h>
+#include <set_ugid.h>
+#include <argv.h>
+
+/* Global library. */
+
+#include <mail_task.h>
+#include <config.h>
+#include <mail_params.h>
+#include <mail_queue.h>
+
+/* Application-specific. */
+
+#define MAX_TEMP_AGE (60 * 60 * 24)    /* temp file maximal age */
+#define STR vstring_str                        /* silly little macro */
+
+#define ACTION_STRUCT  (1<<0)          /* fix file organization */
+#define ACTION_PURGE   (1<<1)          /* purge old temp files */
+
+#define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE)
+
+ /*
+  * Information about queue directories and what we expect to do there. If a
+  * file has unexpected owner permissions and is older than some threshold,
+  * the file is discarded. We don't step into maildrop subdirectories - if
+  * maildrop is writable, we might end up in the wrong place, deleting the
+  * wrong information.
+  */
+struct queue_info {
+    char   *name;                      /* directory name */
+    int     perms;                     /* expected permissions */
+    int     flags;                     /* see below */
+};
+
+#define RECURSE                (1<<0)          /* step into subdirectories */
+#define        DONT_RECURSE    0               /* don't step into directories */
+
+static struct queue_info queue_info[] = {
+    MAIL_QUEUE_MAILDROP, MAIL_QUEUE_STAT_READY, DONT_RECURSE,
+    MAIL_QUEUE_INCOMING, MAIL_QUEUE_STAT_READY, RECURSE,
+    MAIL_QUEUE_ACTIVE, MAIL_QUEUE_STAT_READY, RECURSE,
+    MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE,
+    MAIL_QUEUE_DEFER, 0600, RECURSE,
+    MAIL_QUEUE_BOUNCE, 0600, RECURSE,
+    0,
+};
+
+/* super - check queue file location and clean up */
+
+static void super(char **queues, int action)
+{
+    ARGV   *hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,");
+    VSTRING *actual_path = vstring_alloc(10);
+    VSTRING *wanted_path = vstring_alloc(10);
+    struct stat st;
+    char   *queue_name;
+    SCAN_DIR *info;
+    char   *path;
+    int     actual_depth;
+    int     wanted_depth;
+    char  **cpp;
+    struct queue_info *qp;
+
+    /*
+     * Make sure every file is in the right place, clean out stale files, and
+     * remove non-file/non-directory objects.
+     */
+    while ((queue_name = *queues++) != 0) {
+
+       /*
+        * Look up queue-specific properties: desired hashing depth, what
+        * file permissions to look for, and whether or not it is desirable
+        * to step into subdirectories.
+        */
+       for (qp = queue_info; /* void */ ; qp++) {
+           if (qp->name == 0)
+               msg_fatal("unknown queue name: %s", queue_name);
+           if (strcmp(qp->name, queue_name) == 0)
+               break;
+       }
+       for (cpp = hash_queue_names->argv; /* void */ ; cpp++) {
+           if (*cpp == 0) {
+               wanted_depth = 0;
+               break;
+           }
+           if (strcmp(*cpp, queue_name) == 0) {
+               wanted_depth = var_hash_queue_depth;
+               break;
+           }
+       }
+
+       /*
+        * Sanity check. Some queues just cannot be recursive.
+        */
+       if (wanted_depth > 0 && (qp->flags & RECURSE) == 0)
+           msg_fatal("%s queue must not be hashed", queue_name);
+
+       /*
+        * Other per-directory initialization.
+        */
+       info = scan_dir_open(queue_name);
+       actual_depth = 0;
+
+       for (;;) {
+
+           /*
+            * If we reach the end of a subdirectory, return to its parent.
+            * Delete subdirectories that are no longer needed.
+            */
+           if ((path = scan_dir_next(info)) == 0) {
+               if (actual_depth == 0)
+                   break;
+               if (actual_depth > wanted_depth) {
+                   if (rmdir(scan_dir_path(info)) < 0 && errno != ENOENT)
+                       msg_warn("remove %s: %m", scan_dir_path(info));
+                   else if (msg_verbose)
+                       msg_info("remove %s", scan_dir_path(info));
+               }
+               scan_dir_pop(info);
+               actual_depth--;
+               continue;
+           }
+
+           /*
+            * If we stumble upon a subdirectory, enter it, if it is
+            * considered safe to do so. Otherwise, try to remove the
+            * subdirectory at a later stage.
+            */
+           if (strlen(path) == 1 && (qp->flags & RECURSE) != 0) {
+               actual_depth++;
+               scan_dir_push(info, path);
+               continue;
+           }
+
+           /*
+            * See if this is a stale file or some non-file object. Be
+            * careful not to delete bounce or defer logs just because they
+            * are more than a couple days old.
+            */
+           vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path);
+           if (stat(STR(actual_path), &st) < 0)
+               continue;
+           if (S_ISDIR(st.st_mode)) {
+               if (rmdir(STR(actual_path)) < 0 && errno != ENOENT)
+                   msg_warn("remove subdirectory %s: %m", STR(actual_path));
+               else if (msg_verbose)
+                   msg_info("remove subdirectory %s", STR(actual_path));
+               continue;
+           }
+           if (!S_ISREG(st.st_mode)
+               || ((action & ACTION_PURGE) != 0 &&
+                   (st.st_mode & S_IRWXU) != qp->perms
+                   && time((time_t *) 0) > st.st_mtime + MAX_TEMP_AGE)) {
+               if (remove(STR(actual_path)) < 0 && errno != ENOENT)
+                   msg_warn("remove %s: %m", STR(actual_path));
+               else if (msg_verbose)
+                   msg_info("remove %s", STR(actual_path));
+               continue;
+           }
+
+           /*
+            * See if this file sits in the right place in the file system
+            * hierarchy. Its place may be wrong after a change to the
+            * hash_queue_{names,depth} parameter settings. The implied
+            * mkdir() operation is the main reason for this command to run
+            * with postfix privilege. The mail_queue_mkdirs() routine could
+            * be fixed to use the "right" privilege, but it is a good idea
+            * to do everying with the postfix owner privileges regardless,
+            * in order to limit the amount of damage that we can do.
+            */
+           (void) mail_queue_path(wanted_path, queue_name, path);
+           if (strcmp(STR(actual_path), STR(wanted_path)) != 0) {
+               if (rename(STR(actual_path), STR(wanted_path)) < 0)
+                   if (errno != ENOENT
+                       || mail_queue_mkdirs(STR(wanted_path)) < 0
+                       || rename(STR(actual_path), STR(wanted_path)) < 0)
+                       msg_fatal("rename %s to %s: %m", STR(actual_path),
+                                 STR(wanted_path));
+               if (msg_verbose)
+                   msg_info("rename %s to %s", STR(actual_path),
+                            STR(wanted_path));
+           }
+       }
+       scan_dir_close(info);
+    }
+
+    /*
+     * Clean up.
+     */
+    vstring_free(wanted_path);
+    vstring_free(actual_path);
+    argv_free(hash_queue_names);
+}
+
+main(int argc, char **argv)
+{
+    int     fd;
+    struct stat st;
+    char   *slash;
+    int     debug_me = 0;
+    int     action = 0;
+    char  **queues;
+    int     c;
+
+    /*
+     * Defaults.
+     */
+    static char *default_queues[] = {
+       MAIL_QUEUE_MAILDROP,
+       MAIL_QUEUE_INCOMING,
+       MAIL_QUEUE_ACTIVE,
+       MAIL_QUEUE_DEFERRED,
+       MAIL_QUEUE_DEFER,
+       MAIL_QUEUE_BOUNCE,
+       0,
+    };
+
+    /*
+     * Be consistent with file permissions.
+     */
+    umask(022);
+
+    /*
+     * To minimize confusion, make sure that the standard file descriptors
+     * are open before opening anything else.
+     */
+    for (fd = 0; fd < 3; fd++)
+       if (fstat(fd, &st) == -1 && open("/dev/null", 2) != fd)
+           msg_fatal("open /dev/null: %m");
+
+    /*
+     * Process environment options as early as we can. We might be called
+     * from a set-uid (set-gid) program, so be careful with importing
+     * environment variables.
+     */
+    if (safe_getenv(CONF_ENV_VERB))
+       msg_verbose = 1;
+    if (safe_getenv(CONF_ENV_DEBUG))
+       debug_me = 1;
+
+    /*
+     * Initialize. Set up logging, read the global configuration file and
+     * extract configuration information.
+     */
+    if ((slash = strrchr(argv[0], '/')) != 0)
+       argv[0] = slash + 1;
+    msg_vstream_init(argv[0], VSTREAM_ERR);
+    msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+    set_config_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+
+    read_config();
+    if (chdir(var_queue_dir))
+       msg_fatal("chdir %s: %m", var_queue_dir);
+
+    /*
+     * All file/directory updates must be done as the mail system owner. This
+     * is because Postfix daemons manipulate the queue with those same
+     * privileges, so directories must be created with the right ownership.
+     * 
+     * Running as a non-root user is also required for security reasons. When
+     * the Postfix queue hierarchy is compromised, an attacker could trick us
+     * into entering other file hierarchies and afflicting damage. Running as
+     * a non-root user limits the damage to the already compromised mail
+     * owner.
+     */
+    set_ugid(var_owner_uid, var_owner_gid);
+
+    /*
+     * Parse JCL.
+     */
+    while ((c = GETOPT(argc, argv, "spv")) > 0) {
+       switch (c) {
+       default:
+           msg_fatal("usage: %s [-s (fix structure)] [-p (purge stale files)]",
+                     argv[0]);
+       case 's':
+           action |= ACTION_STRUCT;
+           break;
+       case 'p':
+           action |= ACTION_PURGE;
+           break;
+       case 'v':
+           msg_verbose++;
+           break;
+       }
+    }
+
+    /*
+     * Execute the explicitly specified (or default) action, on the
+     * explicitly specified (or default) queues.
+     */
+    if (action == 0)
+       action = ACTION_DEFAULT;
+    if (argv[optind] == 0)
+       queues = default_queues;
+    else
+       queues = argv + optind;
+
+    super(queues, action);
+
+    exit(0);
+}
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 4688f33bf9cdaa0f890ae21fafe09c7b7fb4222f..4219845f01a441e6aad3a7ad0bd1adb4f1df349e 100644 (file)
@@ -74,6 +74,7 @@ qmgr.o: ../include/iostuff.h
 qmgr.o: ../include/master_proto.h
 qmgr.o: ../include/mail_server.h
 qmgr.o: qmgr.h
+qmgr.o: ../include/scan_dir.h
 qmgr.o: ../include/maps.h
 qmgr_active.o: qmgr_active.c
 qmgr_active.o: ../include/sys_defs.h
@@ -89,7 +90,9 @@ qmgr_active.o: ../include/vstring.h
 qmgr_active.o: ../include/recipient_list.h
 qmgr_active.o: ../include/bounce.h
 qmgr_active.o: ../include/defer.h
+qmgr_active.o: ../include/rec_type.h
 qmgr_active.o: qmgr.h
+qmgr_active.o: ../include/scan_dir.h
 qmgr_active.o: ../include/maps.h
 qmgr_bounce.o: qmgr_bounce.c
 qmgr_bounce.o: ../include/sys_defs.h
@@ -98,6 +101,7 @@ qmgr_bounce.o: ../include/deliver_completed.h
 qmgr_bounce.o: ../include/vstream.h
 qmgr_bounce.o: ../include/vbuf.h
 qmgr_bounce.o: qmgr.h
+qmgr_bounce.o: ../include/scan_dir.h
 qmgr_bounce.o: ../include/maps.h
 qmgr_defer.o: qmgr_defer.c
 qmgr_defer.o: ../include/sys_defs.h
@@ -107,6 +111,7 @@ qmgr_defer.o: ../include/vbuf.h
 qmgr_defer.o: ../include/defer.h
 qmgr_defer.o: ../include/bounce.h
 qmgr_defer.o: qmgr.h
+qmgr_defer.o: ../include/scan_dir.h
 qmgr_defer.o: ../include/maps.h
 qmgr_deliver.o: qmgr_deliver.c
 qmgr_deliver.o: ../include/sys_defs.h
@@ -120,7 +125,9 @@ qmgr_deliver.o: ../include/iostuff.h
 qmgr_deliver.o: ../include/mail_queue.h
 qmgr_deliver.o: ../include/mail_proto.h
 qmgr_deliver.o: ../include/recipient_list.h
+qmgr_deliver.o: ../include/mail_params.h
 qmgr_deliver.o: qmgr.h
+qmgr_deliver.o: ../include/scan_dir.h
 qmgr_deliver.o: ../include/maps.h
 qmgr_enable.o: qmgr_enable.c
 qmgr_enable.o: ../include/sys_defs.h
@@ -128,6 +135,7 @@ qmgr_enable.o: ../include/msg.h
 qmgr_enable.o: ../include/vstream.h
 qmgr_enable.o: ../include/vbuf.h
 qmgr_enable.o: qmgr.h
+qmgr_enable.o: ../include/scan_dir.h
 qmgr_enable.o: ../include/maps.h
 qmgr_entry.o: qmgr_entry.c
 qmgr_entry.o: ../include/sys_defs.h
@@ -138,6 +146,7 @@ qmgr_entry.o: ../include/vstream.h
 qmgr_entry.o: ../include/vbuf.h
 qmgr_entry.o: ../include/mail_params.h
 qmgr_entry.o: qmgr.h
+qmgr_entry.o: ../include/scan_dir.h
 qmgr_entry.o: ../include/maps.h
 qmgr_message.o: qmgr_message.c
 qmgr_message.o: ../include/sys_defs.h
@@ -163,6 +172,7 @@ qmgr_message.o: ../include/maps.h
 qmgr_message.o: ../include/opened.h
 qmgr_message.o: ../include/resolve_clnt.h
 qmgr_message.o: qmgr.h
+qmgr_message.o: ../include/scan_dir.h
 qmgr_move.o: qmgr_move.c
 qmgr_move.o: ../include/sys_defs.h
 qmgr_move.o: ../include/msg.h
@@ -172,6 +182,7 @@ qmgr_move.o: ../include/mail_queue.h
 qmgr_move.o: ../include/vstring.h
 qmgr_move.o: ../include/vbuf.h
 qmgr_move.o: ../include/vstream.h
+qmgr_move.o: ../include/mail_scan_dir.h
 qmgr_move.o: qmgr.h
 qmgr_move.o: ../include/maps.h
 qmgr_queue.o: qmgr_queue.c
@@ -185,6 +196,7 @@ qmgr_queue.o: ../include/recipient_list.h
 qmgr_queue.o: qmgr.h
 qmgr_queue.o: ../include/vstream.h
 qmgr_queue.o: ../include/vbuf.h
+qmgr_queue.o: ../include/scan_dir.h
 qmgr_queue.o: ../include/maps.h
 qmgr_rcpt_list.o: qmgr_rcpt_list.c
 qmgr_rcpt_list.o: ../include/sys_defs.h
@@ -192,12 +204,14 @@ qmgr_rcpt_list.o: ../include/mymalloc.h
 qmgr_rcpt_list.o: qmgr.h
 qmgr_rcpt_list.o: ../include/vstream.h
 qmgr_rcpt_list.o: ../include/vbuf.h
+qmgr_rcpt_list.o: ../include/scan_dir.h
 qmgr_rcpt_list.o: ../include/maps.h
 qmgr_scan.o: qmgr_scan.c
 qmgr_scan.o: ../include/sys_defs.h
 qmgr_scan.o: ../include/msg.h
 qmgr_scan.o: ../include/mymalloc.h
 qmgr_scan.o: ../include/scan_dir.h
+qmgr_scan.o: ../include/mail_scan_dir.h
 qmgr_scan.o: qmgr.h
 qmgr_scan.o: ../include/vstream.h
 qmgr_scan.o: ../include/vbuf.h
@@ -216,4 +230,5 @@ qmgr_transport.o: ../include/recipient_list.h
 qmgr_transport.o: ../include/config.h
 qmgr_transport.o: ../include/mail_params.h
 qmgr_transport.o: qmgr.h
+qmgr_transport.o: ../include/scan_dir.h
 qmgr_transport.o: ../include/maps.h
index 464ee90aad09bf86c075f9354833ea9e4a3b625e..007f298dd7fa705effaac222d660b719702e36ab 100644 (file)
 /* .IP "\fBslow start\fR"
 /*     This strategy eliminates "thundering herd" problems by slowly
 /*     adjusting the number of parallel deliveries to the same destination.
-/* .IP "\fBround robin\fR and \fBrandom walk\fR"
+/* .IP "\fBround robin\fR
 /*     The queue manager sorts delivery requests by destination.
 /*     Round-robin selection prevents one destination from dominating
 /*     deliveries to other destinations.
-/*     Random walk prevents one problematic message from blocking
-/*     deliveries of other mail to the same destination.
 /* .IP "\fBexponential backoff\fR"
 /*     Mail that cannot be delivered upon the first attempt is deferred.
 /*     The time interval between delivery attempts is doubled after each
@@ -276,7 +274,7 @@ MAPS   *qmgr_virtual;
 
 /* qmgr_deferred_run_event - queue manager heartbeat */
 
-static void qmgr_deferred_run_event(char *dummy)
+static void qmgr_deferred_run_event(int unused_event, char *dummy)
 {
 
     /*
@@ -322,9 +320,11 @@ static void qmgr_trigger_event(char *buf, int len,
            break;
        case QMGR_REQ_FLUSH_DEAD:
            deferred_flag |= QMGR_FLUSH_DEAD;
+           incoming_flag |= QMGR_FLUSH_DEAD;
            break;
        case QMGR_REQ_SCAN_ALL:
            deferred_flag |= QMGR_SCAN_ALL;
+           incoming_flag |= QMGR_SCAN_ALL;
            break;
        default:
            if (msg_verbose)
@@ -406,18 +406,22 @@ static void qmgr_post_init(void)
      * This routine runs after the skeleton code has entered the chroot jail.
      * Prevent automatic process suicide after a limited number of client
      * requests or after a limited amount of idle time. Move any left-over
-     * entries from the active queue to the deferred queue, and give them a
+     * entries from the active queue to the incoming queue, and give them a
      * time stamp into the future, in order to allow ongoing deliveries to
      * finish first. Start scanning the incoming and deferred queues.
+     * Left-over active queue entries are moved to the incoming queue because
+     * the incoming queue has priority; moving left-overs to the deferred
+     * queue could cause anomalous delays when "postfix reload/start" are
+     * issued often.
      */
     var_use_limit = 0;
     var_idle_limit = 0;
-    qmgr_move(MAIL_QUEUE_ACTIVE, MAIL_QUEUE_DEFERRED,
-             event_time() + var_queue_run_delay);
+    qmgr_move(MAIL_QUEUE_ACTIVE, MAIL_QUEUE_INCOMING,
+             event_time() + var_min_backoff_time);
     qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING);
     qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED);
     qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START);
-    qmgr_deferred_run_event((char *) 0);
+    qmgr_deferred_run_event(0, (char *) 0);
 }
 
 /* main - the main program */
index c8e6c9e2c6bd7fbfb532a8359308d8837f45b997..7660e4671554699e63ac5427c40d9205879b2485 100644 (file)
@@ -12,6 +12,7 @@
   * Utility library.
   */
 #include <vstream.h>
+#include <scan_dir.h>
 
  /*
   * Global library.
@@ -68,9 +69,13 @@ typedef struct QMGR_SCAN QMGR_SCAN;
 }
 
 #define QMGR_LIST_PREPEND(head, object) { \
-    object->peers.prev = head->prev; \
+    object->peers.prev = head.prev; \
     object->peers.next = 0; \
-    head.prev->next = object; \
+    if (head.prev) { \
+       head.prev->peers.next = object; \
+    } else { \
+       head.next = object; \
+    } \
     head.prev = object; \
 }
 
@@ -106,6 +111,7 @@ struct QMGR_TRANSPORT {
     int     flags;                     /* blocked, etc. */
     char   *name;                      /* transport name */
     int     dest_concurrency_limit;    /* concurrency per domain */
+    int     init_dest_concurrency;     /* init. per-domain concurrency */
     int     recipient_limit;           /* recipients per transaction */
     struct HTABLE *queue_byname;       /* queues indexed by domain */
     QMGR_QUEUE_LIST queue_list;                /* queues, round robin order */
@@ -215,6 +221,8 @@ struct QMGR_MESSAGE {
     int     refcount;                  /* queue entries */
     int     single_rcpt;               /* send one rcpt at a time */
     long    arrival_time;              /* time when queued */
+    long    warn_offset;               /* warning bounce flag offset */
+    time_t  warn_time;                 /* time next warning to be sent */
     long    data_offset;               /* data seek offset */
     char   *queue_name;                        /* queue name */
     char   *queue_id;                  /* queue file */
@@ -232,6 +240,7 @@ extern MAPS *qmgr_relocated;
 extern MAPS *qmgr_virtual;
 
 extern void qmgr_message_free(QMGR_MESSAGE *);
+extern void qmgr_message_update_warn(QMGR_MESSAGE *);
 extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int);
 extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *);
 
@@ -245,7 +254,7 @@ extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *);
  /*
   * qmgr_bounce.c
   */
-extern void qmgr_bounce_recipient(QMGR_MESSAGE *, QMGR_RCPT *, const char *, ...);
+extern void qmgr_bounce_recipient(QMGR_MESSAGE *, QMGR_RCPT *, const char *,...);
 
  /*
   * qmgr_deliver.c
index a9d04cea7582dea6b73d818d4e3e4c8ac420d503..bd7b17bdb29612439d96f88b9d270e8dba40f647 100644 (file)
 #include <recipient_list.h>
 #include <bounce.h>
 #include <defer.h>
+#include <rec_type.h>
 
 /* Application-specific. */
 
@@ -149,16 +150,10 @@ void    qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id)
 
     /*
      * Skip files that have time stamps into the future. They need to cool
-     * down. Future time stamps should appear only in the deferred queue.
-     * Look at the clock before looking at the queue file time stamp. On a
-     * busy day, several seconds may pass between queue manager wakeup and
-     * queue file scanning.
+     * down. Incoming and deferred files can have future time stamps.
      */
     if ((scan_info->flags & QMGR_SCAN_ALL) == 0
        && st.st_mtime > time((time_t *) 0) + 1) {
-       if (strcmp(scan_info->queue, MAIL_QUEUE_DEFERRED) != 0)
-           msg_warn("%s: queue %s: mtime %ld seconds into the future",
-                    queue_id, scan_info->queue, st.st_mtime - event_time());
        if (msg_verbose)
            msg_info("%s: skip %s (%ld seconds)", myname, queue_id,
                     (long) (st.st_mtime - event_time()));
@@ -281,16 +276,28 @@ void    qmgr_active_done(QMGR_MESSAGE *message)
      * If we get to this point we have tried all recipients for this message.
      * If the message is too old, try to bounce it.
      */
+#define HOUR   3600
 #define DAY    86400
 
-    if (message->flags
-       && event_time() > message->arrival_time + var_max_queue_time * DAY) {
-       if (msg_verbose)
-           msg_info("%s: too old, bouncing %s", myname, message->queue_id);
-       message->flags = defer_flush(BOUNCE_FLAG_KEEP,
-                                    message->queue_name,
-                                    message->queue_id,
-                                    message->errors_to);
+    if (message->flags) {
+       if (event_time() > message->arrival_time + var_max_queue_time * DAY) {
+           if (msg_verbose)
+               msg_info("%s: too old, bouncing %s", myname, message->queue_id);
+           message->flags = defer_flush(BOUNCE_FLAG_KEEP,
+                                        message->queue_name,
+                                        message->queue_id,
+                                        message->errors_to);
+       } else if (message->warn_time > 0
+                  && event_time() > message->warn_time) {
+           if (msg_verbose)
+               msg_info("%s: sending defer warning for %s", myname, message->queue_id);
+           if (defer_warn(BOUNCE_FLAG_KEEP,
+                           message->queue_name,
+                           message->queue_id,
+                           message->errors_to) == 0) {
+               qmgr_message_update_warn(message);
+           }
+       }
     }
 
     /*
index cde38b0919b0fa32d4bfba4e43d951fefda2b933..8aefffceb33653b44aba0418304371762fb6932f 100644 (file)
@@ -60,6 +60,7 @@
 #include <mail_queue.h>
 #include <mail_proto.h>
 #include <recipient_list.h>
+#include <mail_params.h>
 
 /* Application-specific. */
 
@@ -135,6 +136,19 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
     }
 }
 
+/* qmgr_deliver_abort - transport response watchdog */
+
+static void qmgr_deliver_abort(int unused_event, char *context)
+{
+    QMGR_ENTRY *entry = (QMGR_ENTRY *) context;
+    QMGR_QUEUE *queue = entry->queue;
+    QMGR_TRANSPORT *transport = queue->transport;
+    QMGR_MESSAGE *message = entry->message;
+
+    msg_fatal("%s: timeout receiving delivery status from transport: %s",
+             message->queue_id, transport->name);
+}
+
 /* qmgr_deliver_update - process delivery status report */
 
 static void qmgr_deliver_update(int unused_event, char *context)
@@ -146,6 +160,11 @@ static void qmgr_deliver_update(int unused_event, char *context)
     VSTRING *reason = vstring_alloc(1);
     int     status;
 
+    /*
+     * The message transport has responded. Stop the watchdog timer.
+     */
+    event_cancel_timer(qmgr_deliver_abort, context);
+
     /*
      * Retrieve the delivery agent status report. The numerical status code
      * indicates if delivery should be tried again. The reason text is sent
@@ -267,4 +286,9 @@ void    qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream)
     entry->stream = stream;
     event_enable_read(vstream_fileno(stream),
                      qmgr_deliver_update, (char *) entry);
+
+    /*
+     * Guard against broken systems.
+     */
+    event_request_timer(qmgr_deliver_abort, (char *) entry, var_ipc_timeout);
 }
index 8277dbe9bca4c7b0ff893ac71a805a897337b347..4c7c65e213a65d66f402d9fe7d2778d92c428926 100644 (file)
 
 QMGR_ENTRY *qmgr_entry_select(QMGR_QUEUE *queue)
 {
-    int     dir = (rand() & 256);      /* low byte has short cycle */
     QMGR_ENTRY *entry;
 
-    if ((entry = (dir ? queue->todo.prev : queue->todo.next)) != 0) {
+    if ((entry = queue->todo.prev) != 0) {
        QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry);
        queue->todo_refcount--;
        QMGR_LIST_APPEND(queue->busy, entry);
index 4d4cfa48abde20d87f25ff743c50a44ce65e5622..c636890483c09c9f310613732ef1f912dfc9ec77 100644 (file)
@@ -19,6 +19,9 @@
 /*
 /*     void    qmgr_message_free(message)
 /*     QMGR_MESSAGE *message;
+/*
+/*     void    qmgr_message_update_warn(message)
+/*     QMGR_MESSAGE *message;
 /* DESCRIPTION
 /*     This module performs en-gross operations on queue messages.
 /*
@@ -50,6 +53,9 @@
 /*     qmgr_message_free() destroys an in-core message structure and makes
 /*     the resources available for reuse. It is an error to destroy
 /*     a message structure that is still referenced by queue entry structures.
+/*
+/*     qmgr_message_update_warn() takes a closed message, opens it, updates
+/*     the warning field, and closes it again.
 /* DIAGNOSTICS
 /*     Warnings: malformed message file. Fatal errors: out of memory.
 /* SEE ALSO
@@ -136,6 +142,8 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
     message->errors_to = 0;
     message->return_receipt = 0;
     message->data_size = 0;
+    message->warn_offset = 0;
+    message->warn_time = 0;
     message->rcpt_offset = 0;
     qmgr_rcpt_list_init(&message->rcpt_list);
     return (message);
@@ -263,6 +271,11 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        } else if (rec_type == REC_TYPE_RRTO) {
            if (message->return_receipt == 0)
                message->return_receipt = mystrdup(start);
+       } else if (rec_type == REC_TYPE_WARN) {
+           if (message->warn_offset == 0) {
+               message->warn_offset = curr_offset;
+               message->warn_time = atol(start);
+           }
        }
     } while (rec_type > 0 && rec_type != REC_TYPE_END);
 
@@ -307,6 +320,23 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
     }
 }
 
+/* qmgr_message_update_warn - update the time of next delay warning */
+
+void    qmgr_message_update_warn(QMGR_MESSAGE *message)
+{
+
+    /*
+     * XXX eventually this should let us schedule multiple warnings, right
+     * now it just allows for one.
+     */
+    if (qmgr_message_open(message)
+       || vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0
+    || rec_fprintf(message->fp, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT, 0L) < 0
+       || vstream_fflush(message->fp))
+       msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
+    qmgr_message_close(message);
+}
+
 /* qmgr_message_sort_compare - compare recipient information */
 
 static int qmgr_message_sort_compare(const void *p1, const void *p2)
index 2551451021240695d858c50b843c2165e614be0d..7f86197ec01f2ae694b083b63ba716cfbe5011d0 100644 (file)
@@ -45,6 +45,7 @@
 /* Global library. */
 
 #include <mail_queue.h>
+#include <mail_scan_dir.h>
 
 /* Application-specific. */
 
@@ -67,7 +68,7 @@ void    qmgr_move(const char *src_queue, const char *dst_queue,
        msg_info("start move queue %s -> %s", src_queue, dst_queue);
 
     queue_dir = scan_dir_open(src_queue);
-    while ((queue_id = scan_dir_next(queue_dir)) != 0) {
+    while ((queue_id = mail_scan_dir_next(queue_dir)) != 0) {
        if (mail_queue_id_ok(queue_id)) {
            if (time_stamp > 0) {
                tbuf.actime = tbuf.modtime = time_stamp;
index 8a41c71b28aa7276cb8b78c11dd768c66190ad4e..f210b547f92dc1c7d303d6cd4b8cf4253b650f9e 100644 (file)
@@ -104,7 +104,7 @@ int     qmgr_queue_count;
 
 /* qmgr_queue_unthrottle_wrapper - in case (char *) != (struct *) */
 
-static void qmgr_queue_unthrottle_wrapper(char *context)
+static void qmgr_queue_unthrottle_wrapper(int unused_event, char *context)
 {
     QMGR_QUEUE *queue = (QMGR_QUEUE *) context;
 
@@ -123,6 +123,7 @@ static void qmgr_queue_unthrottle_wrapper(char *context)
 void    qmgr_queue_unthrottle(QMGR_QUEUE *queue)
 {
     char   *myname = "qmgr_queue_unthrottle";
+    QMGR_TRANSPORT *transport = queue->transport;
 
     if (msg_verbose)
        msg_info("%s: queue %s", myname, queue->name);
@@ -136,6 +137,8 @@ void    qmgr_queue_unthrottle(QMGR_QUEUE *queue)
            msg_panic("%s: queue %s: window 0 reason 0", myname, queue->name);
        myfree(queue->reason);
        queue->reason = 0;
+       queue->window = transport->init_dest_concurrency;
+       return;
     }
 
     /*
@@ -144,9 +147,8 @@ void    qmgr_queue_unthrottle(QMGR_QUEUE *queue)
      * to the actual concurrency + 1, so that qmgr_queue_throttle() takes
      * effect quickly.
      */
-#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
-
-    if (LIMIT_OK(queue->transport->dest_concurrency_limit, queue->window))
+    if (transport->dest_concurrency_limit == 0
+       || transport->dest_concurrency_limit > queue->busy_refcount)
        queue->window = queue->busy_refcount + 1;
 }
 
@@ -167,18 +169,15 @@ void    qmgr_queue_throttle(QMGR_QUEUE *queue, const char *reason)
 
     /*
      * Decrease the destination's concurrency limit until we reach zero, at
-     * which point the destination is declared dead. Set the destination's
-     * concurrency limit to the actual concurrency - 1, so that throttle
-     * operations take effect quickly.
+     * which point the destination is declared dead. Decrease the concurrency
+     * limit by one, instead of using actual concurrency - 1, to avoid
+     * declaring a host dead after just one single delivery failure.
      */
-    queue->window = queue->busy_refcount - 1;
+    if (queue->window > 0)
+       queue->window--;
 
     /*
-     * Special case for a transport that just was declared dead. Gradually
-     * increase the time between the attempts to contact this destination, up
-     * to a configurable upper limit. When the destination is unreachable for
-     * a substantial amount of time, a message will eventually become so old
-     * that it will be bounced.
+     * Special case for a site that just was declared dead.
      */
     if (queue->window == 0) {
        queue->reason = mystrdup(reason);
@@ -250,7 +249,6 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
      * If possible, choose an initial concurrency of > 1 so that one bad
      * message or one bad network won't slow us down unnecessarily.
      */
-#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
 
     queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
     qmgr_queue_count++;
@@ -258,14 +256,11 @@ QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
     queue->todo_refcount = 0;
     queue->busy_refcount = 0;
     queue->transport = transport;
-    if (LIMIT_OK(transport->dest_concurrency_limit, var_init_dest_concurrency))
-       queue->window = var_init_dest_concurrency;
-    else
-       queue->window = transport->dest_concurrency_limit;
+    queue->window = transport->init_dest_concurrency;
     QMGR_LIST_INIT(queue->todo);
     QMGR_LIST_INIT(queue->busy);
     queue->reason = 0;
-    QMGR_LIST_APPEND(transport->queue_list, queue);
+    QMGR_LIST_PREPEND(transport->queue_list, queue);
     htable_enter(transport->queue_byname, site, (char *) queue);
     return (queue);
 }
index f73e1e1ed080ad43aa048d9a076b22d68b8678bb..e0d9fc079abfe478df28c5a686680546156ecb34 100644 (file)
 #include <mymalloc.h>
 #include <scan_dir.h>
 
+/* Global library. */
+
+#include <mail_scan_dir.h>
+
 /* Application-specific. */
 
 #include "qmgr.h"
@@ -129,14 +133,14 @@ char   *qmgr_scan_next(QMGR_SCAN *scan_info)
      * Restart the scan if we reach the end and a queue scan request has
      * arrived in the mean time.
      */
-    if (scan_info->handle && (path = scan_dir_next(scan_info->handle)) == 0) {
+    if (scan_info->handle && (path = mail_scan_dir_next(scan_info->handle)) == 0) {
        scan_info->handle = scan_dir_close(scan_info->handle);
        if (msg_verbose && (scan_info->nflags & QMGR_SCAN_START) == 0)
            msg_info("done %s queue scan", scan_info->queue);
     }
     if (!scan_info->handle && (scan_info->nflags & QMGR_SCAN_START)) {
        qmgr_scan_start(scan_info);
-       path = scan_dir_next(scan_info->handle);
+       path = mail_scan_dir_next(scan_info->handle);
     }
     return (path);
 }
index a10714f56bdfd37be084161c38d3ed262bfaab88..cf3a0d6c8c095ae687bb4989d767e7bfb14666dd 100644 (file)
@@ -107,7 +107,7 @@ struct QMGR_TRANSPORT_ALLOC {
 
 /* qmgr_transport_unthrottle_wrapper - in case (char *) != (struct *) */
 
-static void qmgr_transport_unthrottle_wrapper(char *context)
+static void qmgr_transport_unthrottle_wrapper(int unused_event, char *context)
 {
     qmgr_transport_unthrottle((QMGR_TRANSPORT *) context);
 }
@@ -162,6 +162,15 @@ void    qmgr_transport_throttle(QMGR_TRANSPORT *transport, const char *reason)
     }
 }
 
+/* qmgr_transport_abort - transport connect watchdog */
+
+static void qmgr_transport_abort(int unused_event, char *context)
+{
+    QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
+
+    msg_fatal("timeout connecting to transport: %s", alloc->transport->name);
+}
+
 /* qmgr_transport_event - delivery process availability notice */
 
 static void qmgr_transport_event(int unused_event, char *context)
@@ -175,6 +184,11 @@ static void qmgr_transport_event(int unused_event, char *context)
     if (msg_verbose)
        msg_info("transport_event: %s", alloc->transport->name);
 
+    /*
+     * Connection request completed. Stop the watchdog timer.
+     */
+    event_cancel_timer(qmgr_transport_abort, context);
+
     /*
      * Disable further read events that end up calling this function.
      */
@@ -281,6 +295,11 @@ void    qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT
     alloc->notify = notify;
     transport->flags |= QMGR_TRANSPORT_STAT_BUSY;
     ENABLE_EVENTS(vstream_fileno(alloc->stream), EVENT_HANDLER, (char *) alloc);
+
+    /*
+     * Guard against broken systems.
+     */
+    event_request_timer(qmgr_transport_abort, (char *) alloc, var_ipc_timeout);
 }
 
 /* qmgr_transport_create - create transport instance */
@@ -305,6 +324,12 @@ QMGR_TRANSPORT *qmgr_transport_create(const char *name)
        get_config_int2(name, "_destination_recipient_limit",
                        var_dest_rcpt_limit, 0, 0);
 
+    if (transport->dest_concurrency_limit == 0
+       || transport->dest_concurrency_limit >= var_init_dest_concurrency)
+       transport->init_dest_concurrency = var_init_dest_concurrency;
+    else
+       transport->init_dest_concurrency = transport->dest_concurrency_limit;
+
     transport->queue_byname = htable_create(0);
     QMGR_LIST_INIT(transport->queue_list);
     transport->reason = 0;
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index a7db22a4ce07d748efbb7660c0e7c85606e70e9a..6c1535aaed0eec6eec9f3c2fdeddf87490533de3 100644 (file)
@@ -19,8 +19,8 @@
 /*
 /*     By default, \fBsendmail\fR reads a message from standard input
 /*     and arranges for delivery.  \fBsendmail\fR attempts to create
-/*     a queue file in the \fBmaildrop\fR directory. If the process has
-/*     no write permission, the message is piped through the
+/*     a queue file in the \fBmaildrop\fR directory. If that directory
+/*     is not world-writable, the message is piped through the
 /*     \fBpostdrop\fR(1) command, which is expected to execute with
 /*     suitable privileges.
 /*
 /* .IP "\fB-o \fIx value\fR (ignored)"
 /*     Set option \fIx\fR to \fIvalue\fR. Use the equivalent
 /*     configuration parameter in \fBmain.cf\fR instead.
+/* .IP "\fB-r \fIsender\fR"
+/*     Set the envelope sender address. This is the address where
+/*     delivery problems are sent to, unless the message contains an
+/*     \fBErrors-To:\fR message header.
 /* .IP \fB-q\fR
 /*     Flush the mail queue. This is implemented by kicking the
 /*     \fBqmgr\fR(8) daemon.
@@ -303,6 +307,7 @@ static void enqueue(const char *sender, const char *full_name, char **recipients
     char   *postdrop_command;
     uid_t   uid = getuid();
     int     status;
+    struct stat st;
 
     /*
      * Initialize.
@@ -324,10 +329,12 @@ static void enqueue(const char *sender, const char *full_name, char **recipients
      * Open the queue file. Save the queue file name, so the run-time error
      * handler can clean up in case of errors.
      * 
-     * If the user has no write permission, let the postdrop command open the
+     * If the queue is not world-writable, let the postdrop command open the
      * queue file.
      */
-    if (access(MAIL_QUEUE_MAILDROP, W_OK) == 0) {
+    if (stat(MAIL_QUEUE_MAILDROP, &st) < 0)
+       msg_fatal("No maildrop directory %s: %m", MAIL_QUEUE_MAILDROP);
+    if (st.st_mode & S_IWOTH) {
        handle = mail_stream_file(MAIL_QUEUE_MAILDROP,
                                  MAIL_CLASS_PUBLIC, MAIL_SERVICE_PICKUP);
        sendmail_path = mystrdup(VSTREAM_PATH(handle->stream));
@@ -382,7 +389,7 @@ static void enqueue(const char *sender, const char *full_name, char **recipients
      * delivered intact via SMTP. Strip leading From_ lines. For the benefit
      * of UUCP environments, also get rid of leading >>>From_ lines.
      */
-    rec_fprintf(dst, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0);
+    rec_fprintf(dst, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
     skip_from_ = 1;
     strip_cr = STRIP_CR_DUNNO;
     while ((type = rec_streamlf_get(VSTREAM_IN, buf, var_line_limit))
@@ -635,7 +642,7 @@ int     main(int argc, char **argv)
            optind++;
            continue;
        }
-       if ((c = GETOPT(argc, argv, "B:C:F:IN:R:X:b:ce:f:h:imno:p:q:tvx")) <= 0)
+       if ((c = GETOPT(argc, argv, "B:C:F:IN:R:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
            break;
        switch (c) {
        default:
@@ -701,6 +708,9 @@ int     main(int argc, char **argv)
                break;
            }
            break;
+       case 'r':                               /* obsoleted by -f */
+           sender = optarg;
+           break;
        case 'q':
            if (optarg[0] && !ISDIGIT(optarg[0]))
                msg_fatal("-q%c is not implemented", optarg[0]);
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index efe8d71bdd3f2444fcc98bebd0b7b71b61a7361d..c020235bac4ac4238a824328fd638244a4f5699e 100644 (file)
@@ -69,7 +69,9 @@ showq.o: ../include/mail_proto.h
 showq.o: ../include/iostuff.h
 showq.o: ../include/mail_date.h
 showq.o: ../include/mail_params.h
+showq.o: ../include/mail_scan_dir.h
 showq.o: ../include/config.h
 showq.o: ../include/record.h
 showq.o: ../include/rec_type.h
+showq.o: ../include/htable.h
 showq.o: ../include/mail_server.h
index f6443c2262b2e81e1872ddf9786656851acb0439..8b23e77f2fcd8e8c722b2fbbb0c4b5971a50de3b 100644 (file)
 #include <mail_proto.h>
 #include <mail_date.h>
 #include <mail_params.h>
+#include <mail_scan_dir.h>
 #include <config.h>
 #include <record.h>
 #include <rec_type.h>
+#include <htable.h>
 
 /* Single-threaded server skeleton. */
 
 
 /* Application-specific. */
 
+int     var_dup_filter_limit;
+
 #define STRING_FORMAT  "%-10s %8s %-20s %s\n"
-#define DATA_FORMAT    "%-10s %8ld %20.20s %s\n"
+#define DATA_FORMAT    "%-10s%c%8ld %20.20s %s\n"
+
+static void showq_reasons(VSTREAM *, VSTREAM *, HTABLE *);
 
-static void showq_report(VSTREAM *client, char *id, VSTREAM *qfile, long size, int stop)
+static void showq_report(VSTREAM *client, char *queue, char *id,
+                                VSTREAM *qfile, long size)
 {
     VSTRING *buf = vstring_alloc(100);
     int     rec_type;
     time_t  arrival_time = 0;
     char   *start;
     long    msg_size = 0;
+    VSTREAM *logfile;
+    HTABLE *dup_filter = 0;
+    char    status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : ' ');
 
-    /*
-     * XXX Stop at the designated record type. This is a hack to avoid
-     * listing recipients, so that the defer log can be listed instead.
-     */
     while (!vstream_ferror(client) && (rec_type = rec_get(qfile, buf, 0)) > 0) {
        start = vstring_str(buf);
-       if (rec_type == stop)
-           break;
        switch (rec_type) {
        case REC_TYPE_TIME:
            arrival_time = atol(start);
@@ -114,16 +118,17 @@ static void showq_report(VSTREAM *client, char *id, VSTREAM *qfile, long size, i
        case REC_TYPE_FROM:
            if (*start == 0)
                start = "(MAILER-DAEMON)";
-           vstream_fprintf(client, DATA_FORMAT,
-                     id, msg_size > 0 ? msg_size : size, arrival_time > 0 ?
+           vstream_fprintf(client, DATA_FORMAT, id, status,
+                         msg_size > 0 ? msg_size : size, arrival_time > 0 ?
                            asctime(localtime(&arrival_time)) : "??",
                            printable(start, '?'));
            break;
        case REC_TYPE_RCPT:
-           if (*start == 0)
+           if (*start == 0)                    /* can't happen? */
                start = "(MAILER-DAEMON)";
-           vstream_fprintf(client, STRING_FORMAT,
-                           "", "", "", printable(start, '?'));
+           if (dup_filter == 0 || htable_locate(dup_filter, start) == 0)
+               vstream_fprintf(client, STRING_FORMAT,
+                               "", "", "", printable(start, '?'));
            break;
        case REC_TYPE_MESG:
            if (vstream_fseek(qfile, atol(start), SEEK_SET) < 0)
@@ -132,13 +137,35 @@ static void showq_report(VSTREAM *client, char *id, VSTREAM *qfile, long size, i
        case REC_TYPE_END:
            break;
        }
+
+       /*
+        * With the heading printed, see if there is a defer logfile. The
+        * defer logfile is not necessarily complete: delivery may be
+        * interrupted (postfix stop or reload) before all recipients have
+        * been tried.
+        * 
+        * Therefore we keep a record of recipients found in the defer logfile,
+        * and try to avoid listing those recipients again when processing
+        * the remainder of the queue file.
+        */
+       if (rec_type == REC_TYPE_FROM
+           && dup_filter == 0
+           && (logfile = mail_queue_open(MAIL_QUEUE_DEFER, id,
+                                         O_RDONLY, 0)) != 0) {
+           dup_filter = htable_create(var_dup_filter_limit);
+           showq_reasons(client, logfile, dup_filter);
+           if (vstream_fclose(logfile))
+               msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
+       }
     }
     vstring_free(buf);
+    if (dup_filter)
+       htable_free(dup_filter, (void (*) (char *)) 0);
 }
 
 /* showq_reasons - show deferral reasons */
 
-static void showq_reasons(VSTREAM *client, VSTREAM *logfile)
+static void showq_reasons(VSTREAM *client, VSTREAM *logfile, HTABLE *dup_filter)
 {
     VSTRING *buf = vstring_alloc(100);
     char   *recipient;
@@ -185,6 +212,16 @@ static void showq_reasons(VSTREAM *client, VSTREAM *logfile)
        }
        *cp = 0;
 
+       /*
+        * Update the duplicate filter.
+        */
+       if (*recipient == 0)                    /* can't happen? */
+           recipient = "(MAILER-DAEMON)";
+       if (var_dup_filter_limit == 0
+           || dup_filter->used < var_dup_filter_limit)
+           if (htable_locate(dup_filter, recipient) == 0)
+               htable_enter(dup_filter, recipient, (char *) 0);
+
        /*
         * Find the reason for deferral. Put parentheses around it.
         */
@@ -204,7 +241,8 @@ static void showq_reasons(VSTREAM *client, VSTREAM *logfile)
            saved_reason = mystrdup(reason);
            vstream_fprintf(client, "%78s\n", reason);
        }
-       vstream_fprintf(client, STRING_FORMAT, "", "", "", recipient);
+       vstream_fprintf(client, STRING_FORMAT, "", "", "",
+                       printable(recipient, '?'));
     }
     if (saved_reason)
        myfree(saved_reason);
@@ -218,7 +256,6 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
 {
     char  **queue;
     VSTREAM *qfile;
-    VSTREAM *logfile;
     const char *path;
     int     status;
     char   *id;
@@ -229,6 +266,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
        MAIL_QUEUE_INCOMING,
        MAIL_QUEUE_ACTIVE,
        MAIL_QUEUE_DEFERRED,
+       /* No maildrop until we can disable recursive scans. */
        0,
     };
 
@@ -248,7 +286,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
        SCAN_DIR *scan = scan_dir_open(*queue);
        char   *saved_id = 0;
 
-       while ((id = scan_dir_next(scan)) != 0) {
+       while ((id = mail_scan_dir_next(scan)) != 0) {
 
            /*
             * XXX I have seen showq loop on the same queue id. That would be
@@ -274,18 +312,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
                    vstream_fprintf(client, "\n");
                if ((qfile = mail_queue_open(*queue, id, O_RDONLY, 0)) != 0) {
                    queue_size += st.st_size;
-                   if (strcmp(*queue, MAIL_QUEUE_DEFERRED) == 0
-                       && (logfile = mail_queue_open(MAIL_QUEUE_DEFER, id,
-                                                     O_RDONLY, 0)) != 0) {
-
-                       showq_report(client, id, qfile, (long) st.st_size,
-                                    REC_TYPE_RCPT);
-                       showq_reasons(client, logfile);
-                       if (vstream_fclose(logfile))
-                           msg_warn("close %s %s: %m", MAIL_QUEUE_DEFER, id);
-                   } else {
-                       showq_report(client, id, qfile, (long) st.st_size, 0);
-                   }
+                   showq_report(client, *queue, id, qfile, (long) st.st_size);
                    if (vstream_fclose(qfile))
                        msg_warn("close file %s %s: %m", *queue, id);
                } else if (strcmp(*queue, MAIL_QUEUE_MAILDROP) == 0) {
@@ -316,5 +343,12 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
 
 int     main(int argc, char **argv)
 {
-    single_server_main(argc, argv, showq_service, 0);
+    static CONFIG_INT_TABLE int_table[] = {
+       VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
+       0,
+    };
+
+    single_server_main(argc, argv, showq_service,
+                      MAIL_SERVER_INT_TABLE, int_table,
+                      0);
 }
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 1b63ff9ad71b29a79642cabc3e2545022697fa96..91e217546bcdea4dad0b1a545f3e0749bc4763cb 100644 (file)
@@ -92,6 +92,7 @@ smtp_addr.o: ../include/vstring.h
 smtp_addr.o: ../include/vbuf.h
 smtp_addr.o: ../include/mymalloc.h
 smtp_addr.o: ../include/inet_addr_list.h
+smtp_addr.o: ../include/stringops.h
 smtp_addr.o: ../include/mail_params.h
 smtp_addr.o: ../include/own_inet_addr.h
 smtp_addr.o: ../include/dns.h
index bededd5f591d3f6fc78a0cb929b913d47c0abff7..48274ac305027ee5a7c11d71c9ced38cb45e9a13 100644 (file)
 /*     List of domain or network patterns. When a remote host matches
 /*     a pattern, increase the verbose logging level by the amount
 /*     specified in the \fBdebug_peer_level\fR parameter.
+/* .IP \fBfallback_relay\fR
+/*     Hosts to hand off mail to if a message destination is not found
+/*     or if a destination is unreachable.
+/* .IP \fBignore_mx_lookup_error\fR
+/*     When a name server fails to respond to an MX query, search for an
+/*     A record instead of assuming that the name server will recover.
 /* .IP \fBinet_interfaces\fR
 /*     The network interface addresses that this mail system receives
 /*     mail on. When any of those addresses appears in the list of mail
 /* .IP \fBnotify_classes\fR
 /*     When this parameter includes the \fBprotocol\fR class, send mail to the
 /*     postmaster with transcripts of SMTP sessions with protocol errors.
+/* .IP \fBsmtp_skip_4xx_greeting\fR
+/*     Skip servers that greet us with a 4xx status code.
+/* .IP \fBsmtp_skip_quit_response\fR
+/*     Do not wait for the server response after sending QUIT.
 /* .SH "Resource controls"
 /* .ad
 /* .fi
@@ -178,6 +188,10 @@ char   *var_inet_interfaces;
 char   *var_debug_peer_list;
 int     var_debug_peer_level;
 char   *var_notify_classes;
+int     var_smtp_skip_4xx_greeting;
+int     var_ign_mx_lookup_err;
+int     var_skip_quit_resp;
+char   *var_fallback_relay;
 
  /*
   * Global variables. smtp_errno is set by the address lookup routines and by
@@ -299,6 +313,7 @@ int     main(int argc, char **argv)
     static CONFIG_STR_TABLE str_table[] = {
        VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
        VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+       VAR_FALLBACK_RELAY, DEF_FALLBACK_RELAY, &var_fallback_relay, 0, 0,
        0,
     };
     static CONFIG_INT_TABLE int_table[] = {
@@ -313,10 +328,17 @@ int     main(int argc, char **argv)
        VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
        0,
     };
+    static CONFIG_BOOL_TABLE bool_table[] = {
+       VAR_SMTP_SKIP_4XX, DEF_SMTP_SKIP_4XX, &var_smtp_skip_4xx_greeting,
+       VAR_IGN_MX_LOOKUP_ERR, DEF_IGN_MX_LOOKUP_ERR, &var_ign_mx_lookup_err,
+       VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
+       0,
+    };
 
     single_server_main(argc, argv, smtp_service,
                       MAIL_SERVER_INT_TABLE, int_table,
                       MAIL_SERVER_STR_TABLE, str_table,
+                      MAIL_SERVER_BOOL_TABLE, bool_table,
                       MAIL_SERVER_PRE_INIT, debug_peer_init,
                       0);
 }
index 73ad0972eed6e31846e80d64454eb36789d7034c..f1d2bea13edab8151decb2731e044890dff0cf8f 100644 (file)
 /*     lookups are done via the Internet domain name service (DNS).
 /*     A reasonable number of CNAME indirections is permitted.
 /*
-/*     smtp_domain_addr() looks up the network addresses for mail 
-/*     exchanger hosts listed for the named domain. Addresses are 
+/*     smtp_domain_addr() looks up the network addresses for mail
+/*     exchanger hosts listed for the named domain. Addresses are
 /*     returned in most-preferred first order. The result is truncated
-/*     so that it contains only hosts that are more preferred than the 
+/*     so that it contains only hosts that are more preferred than the
 /*     local mail server itself.
 /*
-/*     When no mail exchanger is listed in the DNS for \fIname\fR, the 
+/*     When no mail exchanger is listed in the DNS for \fIname\fR, the
 /*     request is passed to smtp_host_addr().
 /*
 /*     smtp_host_addr() looks up all addresses listed for the named
@@ -75,6 +75,7 @@
 #include <vstring.h>
 #include <mymalloc.h>
 #include <inet_addr_list.h>
+#include <stringops.h>
 
 /* Global library. */
 
@@ -161,6 +162,83 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
     return (addr_list);
 }
 
+/* smtp_addr_fallback - add list of fallback addresses */
+
+static DNS_RR *smtp_addr_fallback(DNS_RR *addr_list)
+{
+    static DNS_RR *fallback_list = 0;
+    DNS_RR *mx_names;
+    DNS_RR *mx_addr_list;
+    DNS_RR *addr;
+    char   *saved_fallback_relay;
+    char   *cp;
+    char   *relay;
+    int     saved_smtp_errno = smtp_errno;
+    VSTRING *why;
+    DNS_RR *rr;
+    unsigned int pref;
+
+    /*
+     * Build a cached list of fall-back host addresses. Issue a warning when
+     * a fall-back host or domain is not found. This is most likely a local
+     * configuration problem.
+     * 
+     * XXX For the sake of admin-friendliness we want to support MX lookups for
+     * fall-back relays. This comes at a price: the fallback relay lookup
+     * routine almost entirely duplicates the smtp_domain_addr() routine.
+     * 
+     * Fall-back hosts are given a preference that is outside the range of valid
+     * DNS preferences (unsigned 16-bit integer).
+     */
+#define FB_PREF        (0xffff + 1)
+
+    if (fallback_list == 0) {
+       why = vstring_alloc(1);
+       cp = saved_fallback_relay = mystrdup(var_fallback_relay);
+       for (pref = FB_PREF; (relay = mystrtok(&cp, " \t\r\n,")) != 0; pref++) {
+           smtp_errno = 0;
+           switch (dns_lookup(relay, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
+           default:
+               smtp_errno = SMTP_RETRY;
+               break;
+           case DNS_FAIL:
+               smtp_errno = SMTP_FAIL;
+               break;
+           case DNS_OK:
+               mx_addr_list = smtp_addr_list(mx_names, why);
+               dns_rr_free(mx_names);
+               for (addr = mx_addr_list; addr; addr = addr->next)
+                   addr->pref = pref;
+               fallback_list = dns_rr_append(fallback_list, mx_addr_list);
+               break;
+           case DNS_NOTFOUND:
+               fallback_list = smtp_addr_one(fallback_list, relay, pref, why);
+               break;
+           }
+           if (smtp_errno != SMTP_OK)
+               msg_warn("look up fall-back relay %s: %s",
+                        relay, vstring_str(why));
+       }
+       vstring_free(why);
+       myfree(saved_fallback_relay);
+    }
+
+    /*
+     * Append a copy of the fall-back address list to the mail exchanger
+     * address list - which may be an empty list if no mail exchanger was
+     * found.
+     */
+    for (rr = fallback_list; rr; rr = rr->next)
+       addr_list = dns_rr_append(addr_list, dns_rr_copy(rr));
+
+    /*
+     * Clean up.
+     */
+    smtp_errno = saved_smtp_errno;
+
+    return (addr_list);
+}
+
 /* smtp_find_self - spot myself in a crowd of mail exchangers */
 
 static DNS_RR *smtp_find_self(DNS_RR *addr_list)
@@ -241,18 +319,27 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why)
      * truncate the list so that it contains only hosts that are more
      * preferred than myself. When no MX resource records exist, look up the
      * addresses listed for this name.
+     * 
+     * XXX Optionally do A lookups even when the MX lookup didn't complete.
+     * Unfortunately with some DNS servers this is not a transient problem.
      */
     switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
     default:
        smtp_errno = SMTP_RETRY;
+       if (var_ign_mx_lookup_err)
+           addr_list = smtp_host_addr(name, why);
        break;
     case DNS_FAIL:
        smtp_errno = SMTP_FAIL;
+       if (var_ign_mx_lookup_err)
+           addr_list = smtp_host_addr(name, why);
        break;
     case DNS_OK:
        mx_names = dns_rr_sort(mx_names, smtp_compare_mx);
        addr_list = smtp_addr_list(mx_names, why);
        dns_rr_free(mx_names);
+       if (*var_fallback_relay)
+           addr_list = smtp_addr_fallback(addr_list);
        if (msg_verbose)
            smtp_print_addr(name, addr_list);
        if ((self = smtp_find_self(addr_list)) != 0)
@@ -288,6 +375,8 @@ DNS_RR *smtp_host_addr(char *host, VSTRING *why)
                                  (char *) &addr, sizeof(addr));
     } else {
        addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
+       if (*var_fallback_relay)
+           addr_list = smtp_addr_fallback(addr_list);
     }
     if (msg_verbose)
        smtp_print_addr(host, addr_list);
index 132d878da927d3ddc6970ac43ab50a3f6202b1e8..6cd3b208364db39d9ceccd8d11e4aa09c7c65dee 100644 (file)
@@ -128,6 +128,7 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
     int     saved_errno;
     VSTREAM *stream;
     int     ch;
+    unsigned long inaddr;
 
     /*
      * Sanity checks.
@@ -152,14 +153,17 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
      * the mail appears to come from the "right" machine address.
      */
     addr_list = own_inet_addr_list();
-    if (addr_list->used == 1
-       && strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) != 0) {
+    if (addr_list->used == 1) {
        sin.sin_port = 0;
        memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
-       if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
-           msg_warn("%s: bind %s: %m", myname, inet_ntoa(addr_list->addrs[0]));
-       else if (msg_verbose)
-           msg_info("%s: bind %s", myname, inet_ntoa(addr_list->addrs[0]));
+       inaddr = ntohl(sin.sin_addr.s_addr);
+       if (!IN_CLASSA(inaddr)
+       || !((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
+           if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
+               msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
+           if (msg_verbose)
+               msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
+       }
     }
 
     /*
@@ -211,19 +215,15 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
     }
 
     /*
-     * Skip this host if it does not send a numeric response. XXX The
-     * smtp_chat module does allow non-numeric responses, so disallowing them
-     * here seems inconsistent.
+     * Skip this host if it sends a 4xx greeting.
      */
-#if 0
-    if (!ISDIGIT(ch)) {
-       vstring_sprintf(why, "connect to %s: non-numeric server response",
+    if (ch == '4' && var_smtp_skip_4xx_greeting) {
+       vstring_sprintf(why, "connect to %s: server refused mail service",
                        addr->name);
        smtp_errno = SMTP_RETRY;
        vstream_fclose(stream);
        return (0);
     }
-#endif
     vstream_ungetc(stream, ch);
     return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
 }
index 87433cf1e1cb38dd4473ba549461e5850a881b01..b29b5c4184f9d15f386c9877e273693a2d6d9fa7 100644 (file)
 
  /*
   * Sender and receiver state. A session does not necessarily go through a
-  * linear progression, so states should be compared for equality only.
+  * linear progression, but states are guaranteed to not jump backwards.
   * Normal sessions go from MAIL->RCPT->DATA->DOT->QUIT->LAST. The states
   * MAIL, RCPT, and DATA may also be followed by ABORT->QUIT->LAST.
+  * 
+  * By default, the receiver skips the QUIT response. Some SMTP servers
+  * disconnect after responding to ".", and some SMTP servers wait before
+  * responding to QUIT.
   */
 #define SMTP_STATE_MAIL                0
 #define SMTP_STATE_RCPT                1
@@ -265,7 +269,7 @@ int     smtp_xfer(SMTP_STATE *state)
 #define RETURN(x) do { vstring_free(next_command); return (x); } while (0)
 
 #define SENDER_IS_AHEAD \
-       (recv_state != send_state || recv_rcpt != send_rcpt)
+       (recv_state < send_state || recv_rcpt != send_rcpt)
 
 #define SENDER_IN_WAIT_STATE \
        (send_state == SMTP_STATE_DOT || send_state == SMTP_STATE_LAST)
@@ -410,7 +414,8 @@ int     smtp_xfer(SMTP_STATE *state)
                 */
                if (recv_state < SMTP_STATE_MAIL
                    || recv_state > SMTP_STATE_QUIT)
-                   msg_panic("%s: bad receiver state %d", myname, recv_state);
+                   msg_panic("%s: bad receiver state %d (sender state %d)",
+                             myname, recv_state, send_state);
 
                /*
                 * Receive the next server response. Use the proper timeout,
@@ -510,14 +515,16 @@ int     smtp_xfer(SMTP_STATE *state)
                            }
                        }
                    }
-                   recv_state = SMTP_STATE_QUIT;
+                   recv_state = (var_skip_quit_resp ?
+                                 SMTP_STATE_LAST : SMTP_STATE_QUIT);
                    break;
 
                    /*
                     * Ignore the RSET response.
                     */
                case SMTP_STATE_ABORT:
-                   recv_state = SMTP_STATE_QUIT;
+                   recv_state = (var_skip_quit_resp ?
+                                 SMTP_STATE_LAST : SMTP_STATE_QUIT);
                    break;
 
                    /*
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index ad06650847fe3f67276d2ba0997afff86bfde003..436dbd059cefe50bcbe17ffe23380235f63a6160 100644 (file)
@@ -34,8 +34,10 @@ smtpd_token: smtpd_token.c $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
 
 smtpd_check: smtpd_check.c $(SMTPD_CHECK_OBJ) $(LIBS)
+       mv $@.o junk
        $(CC) $(CFLAGS) -DTEST -o $@ smtpd_check.c $(SMTPD_CHECK_OBJ) \
                $(LIBS) $(SYSLIBS)
+       mv junk $@.o
 
 printfck: $(OBJS) $(PROG)
        rm -rf printfck
@@ -49,7 +51,7 @@ lint:
        lint $(DEFS) $(SRCS) $(LINTFIX)
 
 clean:
-       rm -f *.o *core $(PROG) $(TESTPROG) junk *.db *.out
+       rm -f *.o *core $(PROG) $(TESTPROG) junk *.db *.out *.tmp
        rm -rf printfck
 
 tidy:  clean
@@ -65,6 +67,20 @@ depend: $(MAKES)
        done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
        @make -f Makefile.in Makefile
 
+tests: smtpd_check_test smtpd_check_test2
+
+smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref
+       ../postmap/postmap smtpd_check_access
+       ./smtpd_check <smtpd_check.in >smtpd_check.tmp 2>&1
+       diff smtpd_check.ref smtpd_check.tmp
+       rm -f smtpd_check.tmp smtpd_check_access.*
+
+smtpd_check_test2: smtpd_check smtpd_check.in2 smtpd_check.ref2
+       ../postmap/postmap smtpd_check_access
+       ./smtpd_check <smtpd_check.in2 >smtpd_check.tmp 2>&1
+       diff smtpd_check.ref2 smtpd_check.tmp
+       rm -f smtpd_check.tmp smtpd_check_access.*
+
 # do not edit below this line - it is generated by 'make depend'
 smtpd.o: smtpd.c
 smtpd.o: ../include/sys_defs.h
@@ -77,8 +93,8 @@ smtpd.o: ../include/vstring_vstream.h
 smtpd.o: ../include/stringops.h
 smtpd.o: ../include/events.h
 smtpd.o: ../include/smtp_stream.h
-smtpd.o: ../include/peer_name.h
 smtpd.o: ../include/valid_hostname.h
+smtpd.o: ../include/peer_name.h
 smtpd.o: ../include/mail_params.h
 smtpd.o: ../include/record.h
 smtpd.o: ../include/rec_type.h
index a19fe013a2c137dece4e396b68b80fa605cb0d86..5f57eced0bacc45ff35d50217f91d37225274d9c 100644 (file)
@@ -55,6 +55,8 @@
 /* .SH Miscellaneous
 /* .ad
 /* .fi
+/* .IP \fBalways_bcc\fR
+/*     Address to send a copy of each message that enters the system.
 /* .IP \fBcommand_directory\fR
 /*     Location of Postfix support commands (default:
 /*     \fB$program_directory\fR).
 #include <stringops.h>
 #include <events.h>
 #include <smtp_stream.h>
-#include <peer_name.h>
 #include <valid_hostname.h>
 
 /* Global library. */
 
+#include <peer_name.h>
 #include <mail_params.h>
 #include <record.h>
 #include <rec_type.h>
@@ -269,6 +271,8 @@ char   *var_maps_rbl_domains;
 int     var_helo_required;
 int     var_reject_code;
 int     var_smtpd_err_sleep;
+int     var_non_fqdn_code;
+char   *var_always_bcc;
 
  /*
   * Global state, for stand-alone mode queue file cleanup. When this is
@@ -580,6 +584,8 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
      * segment, and prepend our own Received: header. If there is only one
      * recipient, list the recipient address.
      */
+    if (*var_always_bcc)
+       rec_fputs(state->cleanup, REC_TYPE_RCPT, var_always_bcc);
     rec_fputs(state->cleanup, REC_TYPE_MESG, "");
     rec_fprintf(state->cleanup, REC_TYPE_NORM,
                "Received: from %s (%s [%s])",
@@ -1123,6 +1129,7 @@ int     main(int argc, char **argv)
        VAR_ACCESS_MAP_CODE, DEF_ACCESS_MAP_CODE, &var_access_map_code, 0, 0,
        VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0,
        VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
+       VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
@@ -1140,6 +1147,7 @@ int     main(int argc, char **argv)
        VAR_RCPT_CHECKS, DEF_RCPT_CHECKS, &var_rcpt_checks, 0, 0,
        VAR_ETRN_CHECKS, DEF_ETRN_CHECKS, &var_etrn_checks, 0, 0,
        VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0,
+       VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
        0,
     };
 
index b4c407798e45b0039675e606e9a5a61b005e6345..c59fe1e9287a1092f39b9e160f45e292a1ff2508 100644 (file)
 /*     in HELO/EHLO commands.
 /*     This violates the RFC. You must enable this for some popular
 /*     PC mail clients.
+/* .IP reject_non_fqdn_hostname
+/* .IP reject_non_fqdn_sender
+/* .IP reject_non_fqdn_recipient
+/*     Require that the HELO, MAIL FROM or RCPT TO commands specify
+/*     a fully-qualified domain name. The non_fqdn_reject_code parameter
+/*     specifies the error code (default: 504).
 /* .IP reject_invalid_hostname
 /*     Reject the request when the HELO/EHLO hostname does not satisfy RFC
 /*     requirements.  The underscore is considered a legal hostname character,
@@ -264,6 +270,7 @@ static jmp_buf smtpd_check_buf;
   * memory manager routines.
   */
 static RESOLVE_REPLY reply;
+static VSTRING *query;
 static VSTRING *error_text;
 
  /*
@@ -327,6 +334,7 @@ void    smtpd_check_init(void)
      * used for returning error responses.
      */
     resolve_clnt_init(&reply);
+    query = vstring_alloc(10);
     error_text = vstring_alloc(10);
 
     /*
@@ -410,12 +418,66 @@ static int permit_mynetworks(SMTPD_STATE *state)
     return (SMTPD_CHECK_DUNNO);
 }
 
+/* dup_if_truncate - save hostname and truncate if it ends in dot */
+
+static char *dup_if_truncate(char *name)
+{
+    int     len;
+    char   *result;
+
+    /*
+     * Truncate hostnames ending in dot but not dot-dot.
+     */
+    if ((len = strlen(name)) > 1
+       && name[len - 1] == '.'
+       && name[len - 2] != '.') {
+       result = mystrndup(name, len - 1);
+    } else
+       result = name;
+    return (result);
+}
+
+/* reject_invalid_hostaddr - fail if host address is incorrect */
+
+static int reject_invalid_hostaddr(SMTPD_STATE *state, char *addr)
+{
+    char   *myname = "reject_invalid_hostaddr";
+    int     len;
+    char   *test_addr;
+    int     stat;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, addr);
+
+    if (addr[0] == '[' && (len = strlen(addr)) > 2 && addr[len - 1] == ']') {
+       test_addr = mystrndup(&addr[1], len - 2);
+    } else
+       test_addr = addr;
+
+    /*
+     * Validate the address.
+     */
+    if (!valid_hostaddr(test_addr))
+       stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                                 "%d <%s>: Invalid ip address",
+                                 var_bad_name_code, addr);
+    else
+       stat = SMTPD_CHECK_DUNNO;
+
+    /*
+     * Cleanup.
+     */
+    if (test_addr != addr)
+       myfree(test_addr);
+
+    return (stat);
+}
+
 /* reject_invalid_hostname - fail if host/domain syntax is incorrect */
 
 static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
 {
     char   *myname = "reject_invalid_hostname";
-    int     len;
     char   *test_name;
     int     stat;
 
@@ -425,12 +487,7 @@ static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
     /*
      * Truncate hostnames ending in dot but not dot-dot.
      */
-    if ((len = strlen(name)) > 1
-       && name[len - 1] == '.'
-       && name[len - 2] != '.') {
-       test_name = mystrndup(name, len - 1);
-    } else
-       test_name = name;
+    test_name = dup_if_truncate(name);
 
     /*
      * Validate the hostname.
@@ -451,6 +508,41 @@ static int reject_invalid_hostname(SMTPD_STATE *state, char *name)
     return (stat);
 }
 
+/* reject_non_fqdn_hostname - fail if host name is not in fqdn form */
+
+static int reject_non_fqdn_hostname(SMTPD_STATE *state, char *name)
+{
+    char   *myname = "reject_non_fqdn_hostname";
+    char   *test_name;
+    int     stat;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, name);
+
+    /*
+     * Truncate hostnames ending in dot but not dot-dot.
+     */
+    test_name = dup_if_truncate(name);
+
+    /*
+     * Validate the hostname.
+     */
+    if (!valid_hostname(test_name) || !strchr(test_name, '.'))
+       stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                                 "%d <%s>: need fully-qualified hostname",
+                                 var_non_fqdn_code, name);
+    else
+       stat = SMTPD_CHECK_DUNNO;
+
+    /*
+     * Cleanup.
+     */
+    if (test_name != name)
+       myfree(test_name);
+
+    return (stat);
+}
+
 /* reject_unknown_hostname - fail if name has no A or MX record */
 
 static int reject_unknown_hostname(SMTPD_STATE *state, char *name)
@@ -508,8 +600,8 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient)
     /*
      * Resolve the address.
      */
-    canon_addr_internal(reply.recipient, recipient);
-    resolve_clnt_query(STR(reply.recipient), &reply);
+    canon_addr_internal(query, recipient);
+    resolve_clnt_query(STR(query), &reply);
 
     /*
      * Permit if destination is local. XXX This must be generalized for
@@ -591,8 +683,8 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
     /*
      * Resolve the address.
      */
-    canon_addr_internal(reply.recipient, recipient);
-    resolve_clnt_query(STR(reply.recipient), &reply);
+    canon_addr_internal(query, recipient);
+    resolve_clnt_query(STR(query), &reply);
 
     /*
      * If the destination is local, it is acceptable, because we are
@@ -659,6 +751,58 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
     return (SMTPD_CHECK_DUNNO);
 }
 
+/* reject_non_fqdn_address - fail if address is not in fqdn form */
+
+static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr)
+{
+    char   *myname = "reject_non_fqdn_address";
+    char   *domain;
+    char   *test_dom;
+    int     stat;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, addr);
+
+    /*
+     * Locate the domain information.
+     */
+    if ((domain = strrchr(addr, '@')) != 0)
+       domain++;
+    else
+       domain = "";
+
+    /*
+     * Skip forms that we can't handle yet. Permit user@[ip_address].
+     */
+    if (domain[0] == '#')
+       return (SMTPD_CHECK_DUNNO);
+    if (domain[0] == '[' && domain[strlen(domain) - 1] == ']')
+       return (SMTPD_CHECK_OK);
+
+    /*
+     * Truncate names ending in dot but not dot-dot.
+     */
+    test_dom = dup_if_truncate(domain);
+
+    /*
+     * Validate the domain.
+     */
+    if (!*test_dom || !valid_hostname(test_dom) || !strchr(test_dom, '.'))
+       stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
+                                 "%d <%s>: need fully-qualified address",
+                                 var_non_fqdn_code, addr);
+    else
+       stat = SMTPD_CHECK_DUNNO;
+
+    /*
+     * Cleanup.
+     */
+    if (test_dom != domain)
+       myfree(test_dom);
+
+    return (stat);
+}
+
 /* reject_unknown_address - fail if address does not resolve */
 
 static int reject_unknown_address(SMTPD_STATE *state, char *addr)
@@ -672,8 +816,8 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr)
     /*
      * Resolve the address.
      */
-    canon_addr_internal(reply.recipient, addr);
-    resolve_clnt_query(STR(reply.recipient), &reply);
+    canon_addr_internal(query, addr);
+    resolve_clnt_query(STR(query), &reply);
 
     /*
      * Skip local destinations and non-DNS forms.
@@ -842,8 +986,8 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr)
     /*
      * Resolve the address.
      */
-    canon_addr_internal(reply.recipient, addr);
-    resolve_clnt_query(STR(reply.recipient), &reply);
+    canon_addr_internal(query, addr);
+    resolve_clnt_query(STR(query), &reply);
 
     /*
      * Garbage in, garbage out. Every address from canon_addr_internal() and
@@ -927,8 +1071,8 @@ static int reject_maps_rbl(SMTPD_STATE *state)
      */
     if (dns_status == DNS_OK)
        result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
-                                "%d Service unavailable; blocked using %s",
-                                   var_maps_rbl_code, rbl_domain);
+                           "%d Service unavailable; [%s] blocked using %s",
+                               var_maps_rbl_code, state->addr, rbl_domain);
     else
        result = SMTPD_CHECK_DUNNO;
 
@@ -1014,19 +1158,31 @@ static int generic_checks(SMTPD_STATE *state, char *name,
        }
        if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
            if (*state->helo_name != '[')
-               *status = reject_invalid_hostname(state, what);
+               *status = reject_invalid_hostname(state, state->helo_name);
+           else
+               *status = reject_invalid_hostaddr(state, state->helo_name);
            return (1);
        }
        if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
            if (*state->helo_name != '[')
                *status = reject_unknown_hostname(state, state->helo_name);
+           else
+               *status = reject_invalid_hostaddr(state, state->helo_name);
            return (1);
        }
        if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
-           if (state->helo_name && inet_addr(state->helo_name) != INADDR_NONE)
+           if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
+               && (*status = reject_invalid_hostaddr(state, state->helo_name)) == 0)
                *status = SMTPD_CHECK_OK;
            return (1);
        }
+       if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
+           if (*state->helo_name != '[')
+               *status = reject_non_fqdn_hostname(state, state->helo_name);
+           else
+               *status = reject_invalid_hostaddr(state, state->helo_name);
+           return (1);
+       }
     }
 
     /*
@@ -1041,6 +1197,11 @@ static int generic_checks(SMTPD_STATE *state, char *name,
            *status = reject_unknown_address(state, state->sender);
            return (1);
        }
+       if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
+           if (*state->sender)
+               *status = reject_non_fqdn_address(state, state->sender);
+           return (1);
+       }
     }
     return (0);
 }
@@ -1083,6 +1244,7 @@ char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
     char  **cpp;
     char   *name;
     int     status;
+    char   *saved_helo = state->helo_name;
 
     /*
      * Initialize.
@@ -1107,7 +1269,7 @@ char   *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
            break;
     }
     myfree(state->helo_name);
-    state->helo_name = 0;
+    state->helo_name = saved_helo;
     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
 }
 
@@ -1118,6 +1280,7 @@ char   *smtpd_check_mail(SMTPD_STATE *state, char *sender)
     char  **cpp;
     char   *name;
     int     status;
+    char   *saved_sender = state->sender;
 
     /*
      * Initialize.
@@ -1142,7 +1305,7 @@ char   *smtpd_check_mail(SMTPD_STATE *state, char *sender)
            break;
     }
     myfree(state->sender);
-    state->sender = 0;
+    state->sender = saved_sender;
     return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
 }
 
@@ -1173,6 +1336,8 @@ char   *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
            status = permit_mx_backup(state, recipient);
        } else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
            status = check_relay_domains(state, recipient);
+       } else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
+           status = reject_non_fqdn_address(state, recipient);
        } else if (generic_checks(state, name, &cpp, &status, recipient) == 0) {
            msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
            break;
@@ -1277,6 +1442,7 @@ char   *var_client_checks = "";
 char   *var_helo_checks = "";
 char   *var_mail_checks = "";
 char   *var_rcpt_checks = "";
+char   *var_etrn_checks = "";
 char   *var_relay_domains = "";
 char   *var_mynetworks = "";
 char   *var_notify_classes = "";
@@ -1345,6 +1511,7 @@ int     var_relay_code;
 int     var_maps_rbl_code;
 int     var_access_map_code;
 int     var_reject_code;
+int     var_non_fqdn_code;
 
 static INT_TABLE int_table[] = {
     "msg_verbose", 0, &msg_verbose,
@@ -1356,6 +1523,7 @@ static INT_TABLE int_table[] = {
     VAR_MAPS_RBL_CODE, DEF_MAPS_RBL_CODE, &var_maps_rbl_code,
     VAR_ACCESS_MAP_CODE, DEF_ACCESS_MAP_CODE, &var_access_map_code,
     VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code,
+    VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code,
     0,
 };
 
@@ -1392,7 +1560,7 @@ static int int_update(char **argv)
 typedef struct {
     char   *name;
     ARGV  **target;
-} REST_TABLE;
+}       REST_TABLE;
 
 static REST_TABLE rest_table[] = {
     "client_restrictions", &client_restrctions,
@@ -1432,6 +1600,8 @@ void    resolve_clnt_init(RESOLVE_REPLY *reply)
 
 VSTRING *canon_addr_internal(VSTRING *result, const char *addr)
 {
+    if (addr == STR(result))
+       msg_panic("canon_addr_internal: result clobbers input");
     if (strchr(addr, '@') == 0)
        msg_fatal("%s: address rewriting is disabled", addr);
     vstring_strcpy(result, addr);
@@ -1441,6 +1611,8 @@ VSTRING *canon_addr_internal(VSTRING *result, const char *addr)
 
 void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
 {
+    if (addr == STR(reply->recipient))
+       msg_panic("resolve_clnt_query: result clobbers input");
     vstring_strcpy(reply->transport, "foo");
     vstring_strcpy(reply->nexthop, "foo");
     if (strchr(addr, '%'))
@@ -1587,6 +1759,9 @@ main(int argc, char **argv)
     }
     vstring_free(buf);
     smtpd_state_reset(&state);
+#define FREE_STRING(s) { if (s) myfree(s); }
+    FREE_STRING(state.helo_name);
+    FREE_STRING(state.sender);
     exit(0);
 }
 
index 542f9d9c16ae676c02c07f49ea8493fec3100717..a2777351d55e1bf916f6f7fc7a65908fa029332d 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Initialize.
 #
-! ../bin/postmap smtpd_check_access
+#! ../bin/postmap smtpd_check_access
 #msg_verbose 1
 mynetworks 127.0.0.0/8,168.100.189.0/28
 relay_domains porcupine.org
@@ -129,3 +129,43 @@ rcpt foo@porcupine.org
 helo good.domain
 mail foo@bad.domain
 rcpt foo@porcupine.org
+#
+# FQDN restrictions
+#
+helo_restrictions reject_non_fqdn_hostname
+sender_restrictions reject_non_fqdn_sender
+recipient_restrictions reject_non_fqdn_recipient
+helo foo.bar.
+helo foo.bar
+helo foo
+mail foo@foo.bar.
+mail foo@foo.bar
+mail foo@foo
+mail foo
+rcpt foo@foo.bar.
+rcpt foo@foo.bar
+rcpt foo@foo
+rcpt foo
+#
+# Numerical HELO checks
+#
+msg_verbose 1
+helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname
+helo [1.2.3.4]
+helo [321.255.255.255]
+helo [0.255.255.255]
+helo [1.2.3.321]
+helo [1.2.3]
+helo [1.2.3.4.5]
+helo [1..2.3.4]
+helo [.1.2.3.4]
+helo [1.2.3.4.5.]
+helo 1.2.3.4
+helo 321.255.255.255
+helo 0.255.255.255
+helo 1.2.3.321
+helo 1.2.3
+helo 1.2.3.4.5
+helo 1..2.3.4
+helo .1.2.3.4
+helo 1.2.3.4.5.
index a6463f986cf76dc9ba6d5b1cfc9067ec719cff36..4672513077f5bd05fe77a610e82e7ce8e712094a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Initialize.
 #
-! ../bin/postmap smtpd_check_access
+#! ../bin/postmap smtpd_check_access
 #msg_verbose 1
 mynetworks 127.0.0.0/8,168.100.189.0/28
 relay_domains porcupine.org
index 73c72c638ac6ba39ad300f0a46be64be5d8bc3b5..42144270b4593a4dcfdfa63eeede2bc0fb9840e8 100644 (file)
@@ -1,8 +1,7 @@
 >>> #
 >>> # Initialize.
 >>> #
->>> ! ../bin/postmap smtpd_check_access
-exit 0
+>>> #! ../bin/postmap smtpd_check_access
 >>> #msg_verbose 1
 >>> mynetworks 127.0.0.0/8,168.100.189.0/28
 OK
@@ -63,6 +62,7 @@ OK
 >>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname
 OK
 >>> helo 123.123.123.123
+./smtpd_check: warning: valid_hostname: numeric hostname: 123.123.123.123
 ./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <123.123.123.123>: Host not found
 450 <123.123.123.123>: Host not found
 >>> helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
@@ -180,8 +180,8 @@ OK
 >>> client spike.porcupine.org 168.100.189.2
 OK
 >>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; blocked using rbl.maps.vix.com
-550 Service unavailable; blocked using rbl.maps.vix.com
+./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
 >>> #
 >>> # Hybrids
 >>> #
@@ -209,6 +209,7 @@ OK
 ./smtpd_check: reject: RCPT from foo[131.155.210.17]: 550 match bad.domain
 550 match bad.domain
 >>> helo 131.155.210.17
+./smtpd_check: warning: valid_hostname: numeric hostname: 131.155.210.17
 OK
 >>> rcpt foo@porcupine.org
 OK
@@ -240,3 +241,157 @@ OK
 550 <wietse@trouble.org> Access denied
 >>> rcpt wietse@porcupine.org
 OK
+>>> #
+>>> # Deferred restrictions
+>>> #
+>>> client_restrictions permit
+OK
+>>> helo_restrictions permit
+OK
+>>> sender_restrictions permit
+OK
+>>> recipient_restrictions check_helo_access,hash:./smtpd_check_access,check_sender_access,hash:./smtpd_check_access
+OK
+>>> helo bad.domain
+OK
+>>> mail foo@good.domain
+OK
+>>> rcpt foo@porcupine.org
+./smtpd_check: reject: RCPT from foo[131.155.210.17]: 550 match bad.domain
+550 match bad.domain
+>>> helo good.domain
+OK
+>>> mail foo@bad.domain
+OK
+>>> rcpt foo@porcupine.org
+./smtpd_check: reject: RCPT from foo[131.155.210.17]: 550 match bad.domain
+550 match bad.domain
+>>> #
+>>> # FQDN restrictions
+>>> #
+>>> helo_restrictions reject_non_fqdn_hostname
+OK
+>>> sender_restrictions reject_non_fqdn_sender
+OK
+>>> recipient_restrictions reject_non_fqdn_recipient
+OK
+>>> helo foo.bar.
+OK
+>>> helo foo.bar
+OK
+>>> helo foo
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 504 <foo>: need fully-qualified hostname
+504 <foo>: need fully-qualified hostname
+>>> mail foo@foo.bar.
+OK
+>>> mail foo@foo.bar
+OK
+>>> mail foo@foo
+./smtpd_check: reject: MAIL from foo[131.155.210.17]: 504 <foo@foo>: need fully-qualified address
+504 <foo@foo>: need fully-qualified address
+>>> mail foo
+./smtpd_check: reject: MAIL from foo[131.155.210.17]: 504 <foo>: need fully-qualified address
+504 <foo>: need fully-qualified address
+>>> rcpt foo@foo.bar.
+OK
+>>> rcpt foo@foo.bar
+OK
+>>> rcpt foo@foo
+./smtpd_check: reject: RCPT from foo[131.155.210.17]: 504 <foo@foo>: need fully-qualified address
+504 <foo@foo>: need fully-qualified address
+>>> rcpt foo
+./smtpd_check: reject: RCPT from foo[131.155.210.17]: 504 <foo>: need fully-qualified address
+504 <foo>: need fully-qualified address
+>>> #
+>>> # Numerical HELO checks
+>>> #
+>>> msg_verbose 1
+OK
+>>> helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname
+OK
+>>> helo [1.2.3.4]
+./smtpd_check: reject_invalid_hostaddr: [1.2.3.4]
+OK
+>>> helo [321.255.255.255]
+./smtpd_check: reject_invalid_hostaddr: [321.255.255.255]
+./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Invalid ip address
+501 <[321.255.255.255]>: Invalid ip address
+>>> helo [0.255.255.255]
+./smtpd_check: reject_invalid_hostaddr: [0.255.255.255]
+./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Invalid ip address
+501 <[0.255.255.255]>: Invalid ip address
+>>> helo [1.2.3.321]
+./smtpd_check: reject_invalid_hostaddr: [1.2.3.321]
+./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Invalid ip address
+501 <[1.2.3.321]>: Invalid ip address
+>>> helo [1.2.3]
+./smtpd_check: reject_invalid_hostaddr: [1.2.3]
+./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Invalid ip address
+501 <[1.2.3]>: Invalid ip address
+>>> helo [1.2.3.4.5]
+./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5]
+./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Invalid ip address
+501 <[1.2.3.4.5]>: Invalid ip address
+>>> helo [1..2.3.4]
+./smtpd_check: reject_invalid_hostaddr: [1..2.3.4]
+./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Invalid ip address
+501 <[1..2.3.4]>: Invalid ip address
+>>> helo [.1.2.3.4]
+./smtpd_check: reject_invalid_hostaddr: [.1.2.3.4]
+./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Invalid ip address
+501 <[.1.2.3.4]>: Invalid ip address
+>>> helo [1.2.3.4.5.]
+./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5.]
+./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Invalid ip address
+501 <[1.2.3.4.5.]>: Invalid ip address
+>>> helo 1.2.3.4
+./smtpd_check: reject_invalid_hostaddr: 1.2.3.4
+OK
+>>> helo 321.255.255.255
+./smtpd_check: reject_invalid_hostaddr: 321.255.255.255
+./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Invalid ip address
+501 <321.255.255.255>: Invalid ip address
+>>> helo 0.255.255.255
+./smtpd_check: reject_invalid_hostaddr: 0.255.255.255
+./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Invalid ip address
+501 <0.255.255.255>: Invalid ip address
+>>> helo 1.2.3.321
+./smtpd_check: reject_invalid_hostaddr: 1.2.3.321
+./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Invalid ip address
+501 <1.2.3.321>: Invalid ip address
+>>> helo 1.2.3
+./smtpd_check: reject_invalid_hostaddr: 1.2.3
+./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Invalid ip address
+501 <1.2.3>: Invalid ip address
+>>> helo 1.2.3.4.5
+./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5
+./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Invalid ip address
+501 <1.2.3.4.5>: Invalid ip address
+>>> helo 1..2.3.4
+./smtpd_check: reject_invalid_hostaddr: 1..2.3.4
+./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Invalid ip address
+501 <1..2.3.4>: Invalid ip address
+>>> helo .1.2.3.4
+./smtpd_check: reject_invalid_hostaddr: .1.2.3.4
+./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Invalid ip address
+501 <.1.2.3.4>: Invalid ip address
+>>> helo 1.2.3.4.5.
+./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5.
+./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
+./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Invalid ip address
+501 <1.2.3.4.5.>: Invalid ip address
index 82f89c184578688066a97b8a3831ed031e27cc1a..78b1f2bda6e0bc1c880c2039f94cb571dc672d54 100644 (file)
@@ -1,8 +1,7 @@
 >>> #
 >>> # Initialize.
 >>> #
->>> ! ../bin/postmap smtpd_check_access
-exit 0
+>>> #! ../bin/postmap smtpd_check_access
 >>> #msg_verbose 1
 >>> mynetworks 127.0.0.0/8,168.100.189.0/28
 OK
@@ -171,5 +170,5 @@ OK
 >>> client spike.porcupine.org 168.100.189.2
 OK
 >>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; blocked using rbl.maps.vix.com
-550 Service unavailable; blocked using rbl.maps.vix.com
+./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
+550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
diff --git a/postfix/smtpstone/hashed-deferred b/postfix/smtpstone/hashed-deferred
new file mode 100644 (file)
index 0000000..93f0e12
--- /dev/null
@@ -0,0 +1,37 @@
+Delivering 1000 deferred messages over the loopback transport,
+outbound concurrency 10. smtp-sink pipelining disabled. Machine is
+P230, BSD/OS 3.1, 64MB memory.
+
+hashing is 16 directories per level
+
+flat deferred queue
+
+    start: Sun Feb 21 16:42:37 EST 1999
+    done: Feb 21 16:44:35
+    time: 1:58 = 118 seconds
+
+    start: Sun Feb 21 16:48:01 EST 1999
+    done: Feb 21 16:49:51
+    time: 1:50 = 110 seconds
+
+hashed deferred queue, depth=1 (16 directories)
+
+    start: Sun Feb 21 17:29:36 EST 1999
+    done: Feb 21 17:31:32
+    time: 1:56 = 116 seconds
+
+    start: Sun Feb 21 17:33:36 EST 1999
+    done: Feb 21 17:35:24
+    time: 1:48 = 108 seconds
+
+    start: Sun Feb 21 17:37:08 EST 1999
+    done: Feb 21 17:39:02
+    time: 1:52 = 112 seconds
+
+Hashing does not slow down deliveries.
+
+However the problem is scanning an empty deferred queue. On an idle
+machine, it takes some 5 seconds to scan an empty depth=2 deferred
+queue unless the blocks happen to be cached. During those 5 seconds
+the queue manager will not pay attention to I/O from delivery
+agents, which is bad.
diff --git a/postfix/smtpstone/hashed-incoming b/postfix/smtpstone/hashed-incoming
new file mode 100644 (file)
index 0000000..7bb1993
--- /dev/null
@@ -0,0 +1,48 @@
+Sending 1000 messages through postfix over the loopback transport,
+inbound concurrency 10. smtp-sink pipelining disabled. Machine is
+P230, BSD/OS 3.1
+
+accepted = time for postfix to accept all messages
+moved = number of messages delivered by postfix when all mail accepted
+done = time for postfix to deliver last message
+
+hashing is 16 directories per level
+
+flat incoming queue
+
+    start: Sun Feb 21 15:12:44 EST 1999
+    accepted: 66.10 real         0.50 user         1.56 sys
+    moved: 122
+    done: Feb 21 15:15:19
+
+    total time: 2:35 = 155 seconds
+
+    start: Sun Feb 21 15:30:44 EST 1999
+    accepted: 67.47 real         0.48 user         1.60 sys
+    moved:
+    done: Feb 21 15:33:10
+
+    total time: 2:26 = 146 seconds
+
+hashed incoming queue, depth=1 (16 subdirs)
+
+    start: Sun Feb 21 15:39:43 EST 1999
+    accepted: 84.42 real         0.49 user         1.66 sys
+    moved: 144
+    done: Feb 21 15:42:27
+
+    total time: 2:44 = 164 seconds
+
+    start: Sun Feb 21 15:42:43 EST 1999
+    accepted: 84.57 real         0.46 user         1.67 sys
+    moved: 
+    done: Feb 21 15:45:34
+
+    total time: 2:51 = 171 seconds
+
+    start: Sun Feb 21 15:47:11 EST 1999
+    accepted: 84.11 real         0.34 user         1.72 sys
+    moved:
+    done: Feb 21 15:49:54
+
+    total time: 2:43 = 163 seconds
index 025b1321d611c06422eded3233d8ee76e9b55abd..3a2960271e18d0e4b2bc52cde2e37e9149213301 100644 (file)
@@ -2,18 +2,24 @@
 /* NAME
 /*     smtp-sink 8
 /* SUMMARY
-/*     smtp test server
+/*     multi-threaded smtp test server
 /* SYNOPSIS
-/*     smtp-sink [-c] [-v] [host]:port backlog
+/*     smtp-sink [-c] [-p] [-v] [-w delay] [host]:port backlog
 /* DESCRIPTION
 /*      \fIsmtp-sink\fR listens on the named host (or address) and port.
 /*     It takes SMTP messages from the network and throws them away.
+/*     The purpose is to measure SMTP client performance, not protocol
+/*     compliance.
 /*     This program is the complement of the \fIsmtp-source\fR program.
 /* .IP -c
 /*     Display a running counter that is updated whenever an SMTP
 /*     QUIT command is executed.
+/* .IP -p
+/*     Disable ESMTP command pipelining.
 /* .IP -v
 /*     Show the SMTP conversations.
+/* .IP "-w delay"
+/*     Wait \fIdelay\fR seconds before responding to a DATA command.
 /* SEE ALSO
 /*     smtp-source, SMTP test message generator
 /* LICENSE
 
 /* Application-specific. */
 
-struct data_state {
+typedef struct SINK_STATE {
     VSTREAM *stream;
-    int     state;
-};
+    int     data_state;
+    int     (*read) (struct SINK_STATE *);
+} SINK_STATE;
 
 #define ST_ANY                 0
 #define ST_CR                  1
@@ -77,34 +84,65 @@ static int var_tmout;
 static int var_max_line_length;
 static char *var_myhostname;
 static VSTRING *buffer;
-static void command_read(int, char *);
-static void disconnected(VSTREAM *);
+static int command_read(SINK_STATE *);
+static int data_read(SINK_STATE *);
+static void disconnect(SINK_STATE *);
 static int count;
 static int counter;
+static int disable_pipelining;
+static int fixed_delay;
+
+/* ehlo_response - respond to EHLO command */
+
+static void ehlo_response(SINK_STATE *state)
+{
+    smtp_printf(state->stream, "250-%s", var_myhostname);
+    if (!disable_pipelining)
+       smtp_printf(state->stream, "250-PIPELINING");
+    smtp_printf(state->stream, "250 8BITMIME");
+}
+
+/* ok_response - send 250 OK */
+
+static void ok_response(SINK_STATE *state)
+{
+    smtp_printf(state->stream, "250 Ok");
+}
+
+/* data_response - respond to DATA command */
+
+static void data_response(SINK_STATE *state)
+{
+    state->data_state = ST_CR_LF;
+    smtp_printf(state->stream, "354 End data with <CR><LF>.<CR><LF>");
+    state->read = data_read;
+}
 
-/* helo - process HELO/EHLO command */
+/* data_event - delayed response to DATA command */
 
-static void helo(VSTREAM *stream)
+static void data_event(int unused_event, char *context)
 {
-    smtp_printf(stream, "250-%s", var_myhostname);
-    smtp_printf(stream, "250-8BITMIME");
-    smtp_printf(stream, "250 PIPELINING");
+    SINK_STATE *state = (SINK_STATE *) context;
+
+    data_response(state);
 }
 
-/* ok - send 250 OK */
+/* quit_response - respond to QUIT command */
 
-static void ok(VSTREAM *stream)
+static void quit_response(SINK_STATE *state)
 {
-    smtp_printf(stream, "250 Ok");
+    smtp_printf(state->stream, "221 Bye");
+    if (count) {
+       counter++;
+       vstream_printf("%d\r", counter);
+       vstream_fflush(VSTREAM_OUT);
+    }
 }
 
 /* data_read - read data from socket */
 
-static void data_read(int unused_event, char *context)
+static int data_read(SINK_STATE *state)
 {
-    struct data_state *dstate = (struct data_state *) context;
-    VSTREAM *stream = dstate->stream;
-    int     avail;
     int     ch;
     struct data_trans {
        int     state;
@@ -120,10 +158,15 @@ static void data_read(int unused_event, char *context)
     };
     struct data_trans *dp;
 
-    avail = peekfd(vstream_fileno(stream));
-    while (avail-- > 0) {
-       ch = VSTREAM_GETC(stream);
-       for (dp = data_trans; dp->state != dstate->state; dp++)
+    /*
+     * We must avoid blocking I/O, so get out of here as soon as both the
+     * VSTREAM and kernel read buffers dry up.
+     */
+    while (vstream_peek(state->stream) > 0
+          || peekfd(vstream_fileno(state->stream)) > 0) {
+       if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF)
+           return (-1);
+       for (dp = data_trans; dp->state != state->data_state; dp++)
             /* void */ ;
 
        /*
@@ -133,141 +176,134 @@ static void data_read(int unused_event, char *context)
         * (empty line) right before the end of the message data.
         */
        if (ch == dp->want)
-           dstate->state = dp->next_state;
+           state->data_state = dp->next_state;
        else if (ch == data_trans[0].want)
-           dstate->state = data_trans[0].next_state;
+           state->data_state = data_trans[0].next_state;
        else
-           dstate->state = ST_ANY;
-       if (dstate->state == ST_CR_LF_DOT_CR_LF) {
+           state->data_state = ST_ANY;
+       if (state->data_state == ST_CR_LF_DOT_CR_LF) {
            if (msg_verbose)
                msg_info(".");
-           smtp_printf(stream, "250 Ok");
-           event_disable_readwrite(vstream_fileno(stream));
-           event_enable_read(vstream_fileno(stream),
-                             command_read, (char *) stream);
-           myfree((char *) dstate);
+           ok_response(state);
+           state->read = command_read;
+           break;
        }
     }
-}
-
-/* data - process DATA command */
-
-static void data(VSTREAM *stream)
-{
-    struct data_state *dstate = (struct data_state *) mymalloc(sizeof(*dstate));
-
-    dstate->stream = stream;
-    dstate->state = ST_CR_LF;
-    smtp_printf(stream, "354 End data with <CR><LF>.<CR><LF>");
-    event_disable_readwrite(vstream_fileno(stream));
-    event_enable_read(vstream_fileno(stream),
-                     data_read, (char *) dstate);
-}
-
-/* quit - process QUIT command */
-
-static void quit(VSTREAM *stream)
-{
-    smtp_printf(stream, "221 Bye");
-    disconnected(stream);
-    if (count) {
-       counter++;
-       vstream_printf("%d\r", counter);
-       vstream_fflush(VSTREAM_OUT);
-    }
+    return (0);
 }
 
  /*
   * The table of all SMTP commands that we can handle.
   */
-typedef struct COMMAND {
+typedef struct SINK_COMMAND {
     char   *name;
-    void    (*action) (VSTREAM *);
-}       COMMAND;
-
-static COMMAND command_table[] = {
-    "helo", helo,
-    "ehlo", helo,
-    "mail", ok,
-    "rcpt", ok,
-    "data", data,
-    "rset", ok,
-    "noop", ok,
-    "vrfy", ok,
-    "quit", quit,
+    void    (*response) (SINK_STATE *);
+} SINK_COMMAND;
+
+static SINK_COMMAND command_table[] = {
+    "helo", ok_response,
+    "ehlo", ehlo_response,
+    "mail", ok_response,
+    "rcpt", ok_response,
+    "data", data_response,
+    "rset", ok_response,
+    "noop", ok_response,
+    "vrfy", ok_response,
+    "quit", quit_response,
     0,
 };
 
 /* command_read - talk the SMTP protocol, server side */
 
-static void command_read(int unused_event, char *context)
+static int command_read(SINK_STATE *state)
 {
-    VSTREAM *stream = (VSTREAM *) context;
     char   *command;
-    COMMAND *cmdp;
+    SINK_COMMAND *cmdp;
 
-    switch (setjmp(smtp_timeout_buf)) {
+    smtp_get(buffer, state->stream, var_max_line_length);
+    if ((command = strtok(vstring_str(buffer), " \t")) == 0) {
+       smtp_printf(state->stream, "500 Error: unknown command");
+       return (0);
+    }
+    if (msg_verbose)
+       msg_info("%s", command);
+    for (cmdp = command_table; cmdp->name != 0; cmdp++)
+       if (strcasecmp(command, cmdp->name) == 0)
+           break;
+    if (cmdp->name == 0) {
+       smtp_printf(state->stream, "500 Error: unknown command");
+       return (0);
+    }
+    if (cmdp->response == data_response && fixed_delay > 0) {
+       event_request_timer(data_event, (char *) state, fixed_delay);
+    } else {
+       cmdp->response(state);
+       if (cmdp->response == quit_response)
+           return (-1);
+    }
+    return (0);
+}
 
-    default:
-       msg_panic("unknown error reading input");
+/* read_event - handle command or data read events */
 
-    case SMTP_ERR_TIME:
-       smtp_printf(stream, "421 Error: timeout exceeded");
-       msg_warn("timeout reading input");
-       disconnected(stream);
-       break;
+static void read_event(int unused_event, char *context)
+{
+    SINK_STATE *state = (SINK_STATE *) context;
 
-    case SMTP_ERR_EOF:
-       msg_warn("lost connection");
-       disconnected(stream);
-       break;
+    do {
+       switch (setjmp(smtp_timeout_buf)) {
 
-    case 0:
-       smtp_get(buffer, stream, var_max_line_length);
-       if ((command = strtok(vstring_str(buffer), " \t")) == 0) {
-           smtp_printf(stream, "500 Error: unknown command");
-           break;
-       }
-       if (msg_verbose)
-           msg_info("%s", command);
-       for (cmdp = command_table; cmdp->name != 0; cmdp++)
-           if (strcasecmp(command, cmdp->name) == 0)
-               break;
-       if (cmdp->name == 0) {
-           smtp_printf(stream, "500 Error: unknown command");
-           break;
+       default:
+           msg_panic("unknown error reading input");
+
+       case SMTP_ERR_TIME:
+           msg_panic("attempt to read non-readable socket");
+           /* NOTREACHED */
+
+       case SMTP_ERR_EOF:
+           msg_warn("lost connection");
+           disconnect(state);
+           return;
+
+       case 0:
+           if (state->read(state) < 0) {
+               if (msg_verbose)
+                   msg_info("disconnect");
+               disconnect(state);
+               return;
+           }
        }
-       cmdp->action(stream);
-       break;
-    }
+    } while (vstream_peek(state->stream) > 0);
 }
 
-/* disconnected - handle disconnection events */
+/* disconnect - handle disconnection events */
 
-static void disconnected(VSTREAM *stream)
+static void disconnect(SINK_STATE *state)
 {
-    if (msg_verbose)
-       msg_info("disconnect");
-    event_disable_readwrite(vstream_fileno(stream));
-    vstream_fclose(stream);
+    event_disable_readwrite(vstream_fileno(state->stream));
+    vstream_fclose(state->stream);
+    myfree((char *) state);
 }
 
-/* connected - connection established */
+/* connect_event - handle connection events */
 
-static void connected(int unused_event, char *context)
+static void connect_event(int unused_event, char *context)
 {
     int     sock = (int) context;
-    VSTREAM *stream;
+    SINK_STATE *state;
     int     fd;
 
     if ((fd = accept(sock, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) >= 0) {
        if (msg_verbose)
            msg_info("connect");
        non_blocking(fd, NON_BLOCKING);
-       stream = vstream_fdopen(fd, O_RDWR);
-       smtp_timeout_setup(stream, var_tmout);
-       smtp_printf(stream, "220 %s ESMTP", var_myhostname);
-       event_enable_read(fd, command_read, (char *) stream);
+       state = (SINK_STATE *) mymalloc(sizeof(*state));
+       state->stream = vstream_fdopen(fd, O_RDWR);
+       state->read = command_read;
+       state->data_state = 0;
+       smtp_timeout_setup(state->stream, var_tmout);
+       smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
+       event_enable_read(fd, read_event, (char *) state);
     }
 }
 
@@ -275,7 +311,7 @@ static void connected(int unused_event, char *context)
 
 static void usage(char *myname)
 {
-    msg_fatal("usage: %s [-c] [-v] [host]:port backlog", myname);
+    msg_fatal("usage: %s [-c] [-p] [-v] [host]:port backlog", myname);
 }
 
 int     main(int argc, char **argv)
@@ -292,14 +328,21 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "cv")) > 0) {
+    while ((ch = GETOPT(argc, argv, "cpvw:")) > 0) {
        switch (ch) {
        case 'c':
            count++;
            break;
+       case 'p':
+           disable_pipelining = 1;
+           break;
        case 'v':
            msg_verbose++;
            break;
+       case 'w':
+           if ((fixed_delay = atoi(optarg)) <= 0)
+               usage(argv[0]);
+           break;
        default:
            usage(argv[0]);
        }
@@ -319,7 +362,7 @@ int     main(int argc, char **argv)
     /*
      * Start the event handler.
      */
-    event_enable_read(sock, connected, (char *) sock);
+    event_enable_read(sock, connect_event, (char *) sock);
     for (;;)
        event_loop(-1);
 }
index 89780caac4556bcfe09ba21754b62abe5a68eb6b..6aae8f01203e8c6fb53b0aaa430a4a475ea679cf 100644 (file)
@@ -2,7 +2,7 @@
 /* NAME
 /*     smtp-source 8
 /* SUMMARY
-/*     SMTP test generator
+/*     multi-threaded SMTP test generator
 /* SYNOPSIS
 /*     smtp-source [options] host[:port]
 /* DESCRIPTION
 /*     Send the specified number of messages (default: 1).
 /* .IP "-r recipient_count"
 /*     Send the specified number of recipients per transaction (default: 1).
-/*     Recipient names are generated by appending a number to the
+/*     Recipient names are generated by prepending a number to the
 /*     recipient address. The default is one recipient per transaction.
 /* .IP "-s session_count"
 /*     Run the specified number of SMTP sessions in parallel (default: 1).
 /* .IP "-t to"
 /*     Use the specified recipient address (default: <foo@myhostname>).
+/* .IP "-R interval"
+/*     Wait for a random period of time 0 <= n <= interval between messages.
+/*     Suspending one thread does not affect other delivery threads.
+/*     threads keep running.
+/* .IP "-w interval"
+/*     Wait a fixed time between messages.
+/*     Suspending one thread does not affect other delivery threads.
 /* LICENSE
 /* .ad
 /* .fi
@@ -67,6 +74,7 @@
 /* Utility library. */
 
 #include <msg.h>
+#include <msg_vstream.h>
 #include <vstring.h>
 #include <vstream.h>
 #include <vstring_vstream.h>
@@ -91,7 +99,6 @@ typedef struct {
     int     xfer_count;                        /* # of xfers in session */
     int     rcpt_count;                        /* # of recipients to go */
     VSTREAM *stream;                   /* open connection */
-    int     fd;                                /* ditto */
     int     connect_count;             /* # of connect()s to retry */
 } SESSION;
 
@@ -123,6 +130,8 @@ static int counter = 0;
 static int send_helo_first = 1;
 static int send_headers = 1;
 static int connect_count = 1;
+static int random_delay = 0;
+static int fixed_delay = 0;
 
 static void connect_done(int, char *);
 static void send_helo(SESSION *);
@@ -137,6 +146,13 @@ static void dot_done(int, char *);
 static void send_quit(SESSION *);
 static void quit_done(int, char *);
 
+/* random_interval - generate a random value in 0 .. (small) interval */
+
+static int random_interval(int interval)
+{
+    return (rand() % (interval + 1));
+}
+
 /* command - send an SMTP command */
 
 static void command(VSTREAM *stream, char *fmt,...)
@@ -230,30 +246,55 @@ static char *exception_text(int except)
 
 static void startup(SESSION *session)
 {
+    int     fd;
+
     if (message_count-- <= 0) {
        myfree((char *) session);
        session_count--;
        return;
     }
     if (session->stream == 0) {
-       if ((session->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            msg_fatal("socket: %m");
        for (;;) {
            if (session->connect_count == 0)
                msg_fatal("connect: %m");
-           if (!connect(session->fd, (struct sockaddr *) & sin, sizeof(sin)))
+           if (!connect(fd, (struct sockaddr *) & sin, sizeof(sin)))
                break;
            if (session->connect_count-- > 1)
                usleep(10);
        }
-       session->stream = vstream_fdopen(session->fd, O_RDWR);
+       session->stream = vstream_fdopen(fd, O_RDWR);
        smtp_timeout_setup(session->stream, var_timeout);
-       event_enable_read(session->fd, connect_done, (char *) session);
+       event_enable_read(vstream_fileno(session->stream), connect_done, (char *) session);
     } else {
        send_mail(session);
     }
 }
 
+/* start_event - invoke startup from timer context */
+
+static void start_event(int unused_event, char *context)
+{
+    SESSION *session = (SESSION *) context;
+
+    startup(session);
+}
+
+/* start_another - start another session */
+
+static void start_another(SESSION *session)
+{
+    if (random_delay > 0) {
+       event_request_timer(start_event, (char *) session,
+                           random_interval(random_delay));
+    } else if (fixed_delay > 0) {
+       event_request_timer(start_event, (char *) session, fixed_delay);
+    } else {
+       startup(session);
+    }
+}
+
 /* connect_done - send message sender info */
 
 static void connect_done(int unused_event, char *context)
@@ -300,13 +341,13 @@ static void send_helo(SESSION *session)
     /*
      * Prepare for the next event.
      */
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, helo_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), helo_done, (char *) session);
 }
 
 /* helo_done - handle HELO response */
 
-static void helo_done(int unused, char *context)
+static void helo_done(int unused_event, char *context)
 {
     SESSION *session = (SESSION *) context;
     RESPONSE *resp;
@@ -341,8 +382,8 @@ static void send_mail(SESSION *session)
     /*
      * Prepare for the next event.
      */
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, mail_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), mail_done, (char *) session);
 }
 
 /* mail_done - handle MAIL response */
@@ -389,8 +430,8 @@ static void send_rcpt(int unused_event, char *context)
     /*
      * Prepare for the next event.
      */
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, rcpt_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), rcpt_done, (char *) session);
 }
 
 /* rcpt_done - handle RCPT completion */
@@ -436,8 +477,8 @@ static void send_data(int unused_event, char *context)
     /*
      * Prepare for the next event.
      */
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, data_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), data_done, (char *) session);
 }
 
 /* data_done - send message content */
@@ -470,7 +511,7 @@ static void data_done(int unused_event, char *context)
        smtp_printf(session->stream, "To: <%s>", recipient);
        smtp_printf(session->stream, "Date: %s", mydate);
        smtp_printf(session->stream, "Message-Id: <%04x.%04x.%04x@%s>",
-                   mypid, session->fd, message_count, var_myhostname);
+                   mypid, vstream_fileno(session->stream), message_count, var_myhostname);
        smtp_fputs("", 0, session->stream);
     }
 
@@ -505,8 +546,8 @@ static void data_done(int unused_event, char *context)
     /*
      * Prepare for the next event.
      */
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, dot_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), dot_done, (char *) session);
 }
 
 /* dot_done - send QUIT */
@@ -532,8 +573,8 @@ static void dot_done(int unused_event, char *context)
     if (disconnect || message_count < 1) {
        send_quit(session);
     } else {
-       event_disable_readwrite(session->fd);
-       startup(session);
+       event_disable_readwrite(vstream_fileno(session->stream));
+       start_another(session);
     }
 }
 
@@ -542,8 +583,8 @@ static void dot_done(int unused_event, char *context)
 static void send_quit(SESSION *session)
 {
     command(session->stream, "QUIT");
-    event_disable_readwrite(session->fd);
-    event_enable_read(session->fd, quit_done, (char *) session);
+    event_disable_readwrite(vstream_fileno(session->stream));
+    event_enable_read(vstream_fileno(session->stream), quit_done, (char *) session);
 }
 
 /* quit_done - disconnect */
@@ -553,17 +594,17 @@ static void quit_done(int unused_event, char *context)
     SESSION *session = (SESSION *) context;
 
     (void) response(session->stream, buffer);
-    event_disable_readwrite(session->fd);
+    event_disable_readwrite(vstream_fileno(session->stream));
     vstream_fclose(session->stream);
     session->stream = 0;
-    startup(session);
+    start_another(session);
 }
 
 /* usage - explain */
 
 static void usage(char *myname)
 {
-    msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -v host[:port]", myname);
+    msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -R delay -v -w delay host[:port]", myname);
 }
 
 /* main - parse JCL and start the machine */
@@ -578,11 +619,12 @@ int     main(int argc, char **argv)
     int     i;
 
     signal(SIGPIPE, SIG_IGN);
+    msg_vstream_init(argv[0], VSTREAM_ERR);
 
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "cC:df:l:m:or:s:t:v")) > 0) {
+    while ((ch = GETOPT(argc, argv, "cC:df:l:m:or:R:s:t:vw:")) > 0) {
        switch (ch) {
        case 'c':
            count++;
@@ -619,6 +661,10 @@ int     main(int argc, char **argv)
            if ((recipients = atoi(optarg)) <= 0)
                usage(argv[0]);
            break;
+       case 'R':
+           if (fixed_delay > 0 || (random_delay = atoi(optarg)) <= 0)
+               usage(argv[0]);
+           break;
        case 's':
            if ((sessions = atoi(optarg)) <= 0)
                usage(argv[0]);
@@ -629,6 +675,10 @@ int     main(int argc, char **argv)
        case 'v':
            msg_verbose++;
            break;
+       case 'w':
+           if (random_delay > 0 || (fixed_delay = atoi(optarg)) <= 0)
+               usage(argv[0]);
+           break;
        default:
            usage(argv[0]);
        }
@@ -638,6 +688,9 @@ int     main(int argc, char **argv)
     if ((port = split_at(host = argv[optind], ':')) == 0)
        port = "smtp";
 
+    if (random_delay > 0)
+       srand(getpid());
+
     /*
      * Translate endpoint address to internal form.
      */
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index 6cae7d8a31793b01936dfb8d37354f0fb515a83b..b2dc90587f0c65bffaf39efeb12a41913892160d 100644 (file)
@@ -90,6 +90,12 @@ void    rewrite_tree(char *unused_ruleset, TOK822 *tree)
     TOK822 *bang;
     TOK822 *local;
 
+    /*
+     * Sanity check.
+     */
+    if (tree->head == 0)
+       msg_panic("rewrite_tree: empty tree");
+
     /*
      * An empty address is a special case.
      */
@@ -152,6 +158,15 @@ void    rewrite_addr(char *ruleset, char *addr, VSTRING *result)
 {
     TOK822 *tree;
 
+    /*
+     * Sanity check. An address is supposed to be in externalized form.
+     */
+    if (*addr == 0) {
+       msg_warn("rewrite_addr: null address, ruleset \"%s\"", ruleset);
+       vstring_strcpy(result, addr);
+       return;
+    }
+
     /*
      * Convert the address from externalized (quoted) form to token list,
      * rewrite it, and convert back.
index 4072501146a299e63930278804e710c3175a54cf..4b6eabcd18b3ccd9237d6a94c93e94e52ec5a43f 100644 (file)
@@ -86,7 +86,6 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
     const char *name;
     const char *value;
     const char *host;
-    const char *next;
     char   *saved_value;
     char   *transport;
     int     found = 0;
@@ -96,8 +95,7 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
 
     /*
      * Keep stripping domain components until nothing is left or until a
-     * matching entry is found. Don't do routing on top-level domains.
-     * Transport table lookups are expensive enough already.
+     * matching entry is found.
      * 
      * After checking the full name, check for .upper.domain, to distinguish
      * between the upper domain and it's decendants, ala sendmail and tcp
@@ -106,7 +104,7 @@ int     transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop)
      * Before changing the DB lookup result, make a copy first, in order to
      * avoid DB cache corruption.
      */
-    for (name = low_domain; (next = strchr(name + 1, '.')) != 0; name = next) {
+    for (name = low_domain; name != 0; name = strchr(name + 1, '.')) {
        if ((value = maps_find(transport_path, name)) != 0) {
            saved_value = mystrdup(value);
            if ((host = split_at(saved_value, ':')) == 0 || *host == 0)
index e59d396add4e27f69acca15c76a5afc1b824979e..b38eded21dd1f4fcfd647ffbe74cf208d972e5a3 100644 (file)
@@ -6,6 +6,7 @@
 -TBOUNCE_STAT
 -TCLEANUP_STATE
 -TCLIENT_LIST
+-TCLNT_STREAM
 -TCONFIG_BOOL_FN_TABLE
 -TCONFIG_BOOL_TABLE
 -TCONFIG_INT_FN_TABLE
@@ -25,6 +26,8 @@
 -TDICT_NISPLUS
 -TDICT_NODE
 -TDICT_OPEN_INFO
+-TDICT_PCRE
+-TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
 -TRECIPIENT_LIST
 -TREC_TYPE_NAME
 -TRESOLVE_REPLY
+-TRESPONSE
 -TSCAN_DIR
+-TSCAN_INFO
+-TSCAN_OBJ
+-TSESSION
 -TSINGLE_SERVER
+-TSINK_COMMAND
+-TSINK_STATE
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTP_ADDR
index f75571ff5e4705376556383b6b3cf21f5bd4f61e..04c65102ef2e4ac4c8adc36b060985f8b06879b2 100644 (file)
@@ -2,8 +2,8 @@ SHELL   = /bin/sh
 SRCS   = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
        close_on_exec.c concatenate.c dict.c dict_db.c dict_dbm.c \
        dict_env.c dict_ht.c dict_ldap.c dict_ni.c dict_nis.c \
-       dict_nisplus.c dict_open.c dir_forest.c environ.c events.c \
-       exec_command.c fifo_listen.c fifo_trigger.c file_limit.c \
+       dict_nisplus.c dict_open.c dir_forest.c doze.c environ.c \
+       events.c exec_command.c fifo_listen.c fifo_trigger.c file_limit.c \
        find_inet.c fsspace.c fullname.c get_domainname.c get_hostname.c \
        htable.c inet_addr_host.c inet_addr_list.c inet_addr_local.c \
        inet_connect.c inet_listen.c inet_trigger.c inet_util.c \
@@ -11,19 +11,19 @@ SRCS        = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
        match_list.c match_ops.c msg.c msg_output.c msg_syslog.c \
        msg_vstream.c mvect.c myflock.c mymalloc.c mystrtok.c name_mask.c \
        non_blocking.c open_as.c open_limit.c open_lock.c peekfd.c \
-       peer_name.c percentm.c posix_signals.c printable.c read_wait.c \
-       readable.c readline.c ring.c safe_getenv.c safe_open.c \
-       sane_accept.c scan_dir.c set_eugid.c set_ugid.c sigdelay.c \
-       skipblanks.c split_at.c stat_as.c sys_compat.c timed_connect.c \
-       timed_wait.c translit.c trimblanks.c unix_connect.c unix_listen.c \
-       unix_trigger.c unsafe.c username.c valid_hostname.c vbuf.c \
-       vbuf_print.c vstream.c vstream_popen.c vstring.c vstring_vstream.c \
-       writable.c write_buf.c write_wait.c doze.c
+       percentm.c posix_signals.c printable.c read_wait.c readable.c \
+       readline.c ring.c safe_getenv.c safe_open.c sane_accept.c \
+       scan_dir.c set_eugid.c set_ugid.c sigdelay.c skipblanks.c \
+       split_at.c stat_as.c sys_compat.c timed_connect.c timed_wait.c \
+       translit.c trimblanks.c unix_connect.c unix_listen.c unix_trigger.c \
+       unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \
+       vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \
+       write_buf.c write_wait.c dict_unix.c dict_pcre.c
 OBJS   = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
        dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \
-       dict_nisplus.o dict_open.o dir_forest.o environ.o events.o \
-       exec_command.o fifo_listen.o fifo_trigger.o file_limit.o \
+       dict_nisplus.o dict_open.o dir_forest.o doze.o environ.o \
+       events.o exec_command.o fifo_listen.o fifo_trigger.o file_limit.o \
        find_inet.o fsspace.o fullname.o get_domainname.o get_hostname.o \
        htable.o inet_addr_host.o inet_addr_list.o inet_addr_local.o \
        inet_connect.o inet_listen.o inet_trigger.o inet_util.o \
@@ -31,14 +31,14 @@ OBJS        = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        match_list.o match_ops.o msg.o msg_output.o msg_syslog.o \
        msg_vstream.o mvect.o myflock.o mymalloc.o mystrtok.o name_mask.o \
        non_blocking.o open_as.o open_limit.o open_lock.o peekfd.o \
-       peer_name.o percentm.o posix_signals.o printable.o read_wait.o \
-       readable.o readline.o ring.o safe_getenv.o safe_open.o \
-       sane_accept.o scan_dir.o set_eugid.o set_ugid.o sigdelay.o \
-       skipblanks.o split_at.o stat_as.o sys_compat.o timed_connect.o \
-       timed_wait.o translit.o trimblanks.o unix_connect.o unix_listen.o \
-       unix_trigger.o unsafe.o username.o valid_hostname.o vbuf.o \
-       vbuf_print.o vstream.o vstream_popen.o vstring.o vstring_vstream.o \
-       writable.o write_buf.o write_wait.o doze.o
+       percentm.o posix_signals.o printable.o read_wait.o readable.o \
+       readline.o ring.o safe_getenv.o safe_open.o sane_accept.o \
+       scan_dir.o set_eugid.o set_ugid.o sigdelay.o skipblanks.o \
+       split_at.o stat_as.o sys_compat.o timed_connect.o timed_wait.o \
+       translit.o trimblanks.o unix_connect.o unix_listen.o unix_trigger.o \
+       unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \
+       vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \
+       write_buf.o write_wait.o dict_unix.o dict_pcre.o
 HDRS   = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \
        dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \
@@ -47,12 +47,13 @@ HDRS        = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        iostuff.h line_wrap.h listen.h lstat_as.h mac_parse.h make_dirs.h \
        match_list.h match_ops.h msg.h msg_output.h msg_syslog.h \
        msg_vstream.h mvect.h myflock.h mymalloc.h name_mask.h open_as.h \
-       open_lock.h peer_name.h percentm.h posix_signals.h readline.h \
-       ring.h safe.h safe_open.h sane_accept.h scan_dir.h set_eugid.h \
-       set_ugid.h sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \
+       open_lock.h percentm.h posix_signals.h readline.h ring.h safe.h \
+       safe_open.h sane_accept.h scan_dir.h set_eugid.h set_ugid.h \
+       sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \
        timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
-       vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h
-TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c
+       vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
+       dict_unix.h dict_pcre.h
+TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
        -Wunused 
@@ -65,7 +66,7 @@ TESTPROG= dict_open events exec_command fifo_open fifo_rdonly_bug \
        fifo_rdwr_bug fifo_trigger fsspace fullname inet_addr_host \
        inet_addr_local mac_parse make_dirs msg_syslog \
        mystrtok peer_name sigdelay translit valid_hostname vstream_popen \
-       vstring vstring_vstream doze
+       vstring vstring_vstream doze select_bug
 
 LIB_DIR        = ../lib
 INC_DIR        = ../include
@@ -109,7 +110,7 @@ lint:
        lint $(SRCS)
 
 clean:
-       rm -f *.o $(LIB) *core $(TESTPROG) junk $(MAKES) 
+       rm -f *.o $(LIB) *core $(TESTPROG) junk $(MAKES) *.tmp
        rm -rf printfck
 
 tidy:  clean
@@ -178,6 +179,9 @@ fifo_rdwr_bug: fifo_rdwr_bug.c $(LIB)
 fifo_rdonly_bug: fifo_rdonly_bug.c $(LIB)
        $(CC) $(CFLAGS)  -o $@ $@.c $(LIB) $(SYSLIBS)
 
+select_bug: select_bug.c $(LIB)
+       $(CC) $(CFLAGS)  -o $@ $@.c $(LIB) $(SYSLIBS)
+
 translit: $(LIB)
        mv $@.o junk
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
@@ -231,6 +235,13 @@ depend: $(MAKES)
        done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
        @make Makefile
 
+tests: valid_hostname_test
+
+valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
+       ./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
+       diff valid_hostname.ref valid_hostname.tmp
+       rm -f valid_hostname.tmp
+
 # do not edit below this line - it is generated by 'make depend'
 argv.o: argv.c
 argv.o: mymalloc.h
@@ -310,10 +321,6 @@ dict_ht.o: vbuf.h
 dict_ht.o: dict_ht.h
 dict_ldap.o: dict_ldap.c
 dict_ldap.o: sys_defs.h
-dict_ldap.o: dict.h
-dict_ldap.o: vstream.h
-dict_ldap.o: vbuf.h
-dict_ldap.o: dict_ldap.h
 dict_ni.o: dict_ni.c
 dict_ni.o: sys_defs.h
 dict_nis.o: dict_nis.c
@@ -343,14 +350,27 @@ dict_open.o: dict.h
 dict_open.o: vstream.h
 dict_open.o: vbuf.h
 dict_open.o: dict_env.h
+dict_open.o: dict_unix.h
 dict_open.o: dict_dbm.h
 dict_open.o: dict_db.h
 dict_open.o: dict_nis.h
 dict_open.o: dict_nisplus.h
 dict_open.o: dict_ni.h
 dict_open.o: dict_ldap.h
+dict_open.o: dict_pcre.h
 dict_open.o: stringops.h
 dict_open.o: split_at.h
+dict_pcre.o: dict_pcre.c
+dict_pcre.o: sys_defs.h
+dict_unix.o: dict_unix.c
+dict_unix.o: sys_defs.h
+dict_unix.o: msg.h
+dict_unix.o: mymalloc.h
+dict_unix.o: vstring.h
+dict_unix.o: vbuf.h
+dict_unix.o: dict.h
+dict_unix.o: vstream.h
+dict_unix.o: dict_unix.h
 dir_forest.o: dir_forest.c
 dir_forest.o: sys_defs.h
 dir_forest.o: msg.h
@@ -588,11 +608,6 @@ open_lock.o: open_lock.h
 peekfd.o: peekfd.c
 peekfd.o: sys_defs.h
 peekfd.o: iostuff.h
-peer_name.o: peer_name.c
-peer_name.o: sys_defs.h
-peer_name.o: msg.h
-peer_name.o: valid_hostname.h
-peer_name.o: peer_name.h
 percentm.o: percentm.c
 percentm.o: sys_defs.h
 percentm.o: vstring.h
@@ -636,7 +651,16 @@ scan_dir.o: scan_dir.c
 scan_dir.o: sys_defs.h
 scan_dir.o: msg.h
 scan_dir.o: mymalloc.h
+scan_dir.o: stringops.h
+scan_dir.o: vstring.h
+scan_dir.o: vbuf.h
 scan_dir.o: scan_dir.h
+select_bug.o: select_bug.c
+select_bug.o: sys_defs.h
+select_bug.o: msg.h
+select_bug.o: vstream.h
+select_bug.o: vbuf.h
+select_bug.o: msg_vstream.h
 set_eugid.o: set_eugid.c
 set_eugid.o: sys_defs.h
 set_eugid.o: msg.h
index 0ab34989d019a2ec4c87b4cb6bacfc53ce232cce..8c9ca7dab224faa16b5f330746ec2c3b76d3ff2a 100644 (file)
 /*     BINHASH *table;
 /*     void    (*free_fn)(char *);
 /*
-/*     void    binhash_walk(table, action)
+/*     void    binhash_walk(table, action, ptr)
 /*     BINHASH *table;
-/*     void    (*action)(BINHASH_INFO *);
+/*     void    (*action)(BINHASH_INFO *info, char *ptr);
+/*     char    *ptr;
 /*
 /*     BINHASH_INFO **binhash_list(table)
 /*     BINHASH *table;
@@ -84,7 +85,8 @@
 /*     with the entry.
 /*
 /*     binhash_walk() invokes the action function for each table entry, with
-/*     a pointer to the entry as its argument.
+/*     a pointer to the entry as its argument. The ptr argument is passed
+/*     on to the action function.
 /*
 /*     binhash_list() returns a null-terminated list of pointers to
 /*     all elements in the named table. The list should be passed to
@@ -303,8 +305,8 @@ void    binhash_free(BINHASH *table, void (*free_fn) (char *))
 
 /* binhash_walk - iterate over hash table */
 
-void    binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *))
-{
+void    binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *, char *),
+                            char *ptr) {
     if (table != 0) {
        unsigned i = table->size;
        BINHASH_INFO **h = table->data;
@@ -312,7 +314,7 @@ void    binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *))
 
        while (i-- > 0)
            for (ht = *h++; ht; ht = ht->next)
-               (*action) (ht);
+               (*action) (ht, ptr);
     }
 }
 
index 814ec8ad3956a41a28ecba06ef8af18ba077eae0..f94e35beeade136a2f5b4fcaf4cf2e2b31470159 100644 (file)
@@ -35,7 +35,7 @@ extern BINHASH_INFO *binhash_locate(BINHASH *, const char *, int);
 extern char *binhash_find(BINHASH *, const char *, int);
 extern void binhash_delete(BINHASH *, const char *, int, void (*) (char *));
 extern void binhash_free(BINHASH *, void (*) (char *));
-extern void binhash_walk(BINHASH *, void (*) (BINHASH_INFO *));
+extern void binhash_walk(BINHASH *, void (*) (BINHASH_INFO *, char *), char *);
 extern BINHASH_INFO **binhash_list(BINHASH *);
 
 /* LICENSE
index 1d38b09fa7ff062e5335b44e07eb1aa820f90588..0e34c93753e16a09cbed907b05f86b9d34d8fbef 100644 (file)
@@ -74,6 +74,9 @@ typedef struct {
 #define DICT_DB_TRY0NULL       (1<<0)
 #define DICT_DB_TRY1NULL       (1<<1)
 
+#define DICT_DB_CACHE_SIZE     (1024 * 1024)
+#define DICT_DB_NELM   4096
+
 /* dict_db_lookup - find database entry */
 
 static const char *dict_db_lookup(DICT *dict, const char *name)
@@ -185,19 +188,14 @@ static void dict_db_close(DICT *dict)
 
 /* dict_db_open - open data base */
 
-static DICT *dict_db_open(const char *path, int flags, int type)
+static DICT *dict_db_open(const char *path, int flags, int type, void *tweak)
 {
     DICT_DB *dict_db;
     DB     *db;
     char   *db_path;
-    HASHINFO tweak;
-
-    memset((char *) &tweak, 0, sizeof(tweak));
-    tweak.nelem = 4096;
-    tweak.cachesize = 1024 * 1024;
 
     db_path = concatenate(path, ".db", (char *) 0);
-    if ((db = dbopen(db_path, flags, 0644, type, (void *) &tweak)) == 0)
+    if ((db = dbopen(db_path, flags, 0644, type, tweak)) == 0)
        msg_fatal("open database %s: %m", db_path);
 
     dict_db = (DICT_DB *) mymalloc(sizeof(*dict_db));
@@ -216,14 +214,24 @@ static DICT *dict_db_open(const char *path, int flags, int type)
 
 DICT   *dict_hash_open(const char *path, int flags)
 {
-    return (dict_db_open(path, flags, DB_HASH));
+    HASHINFO tweak;
+
+    memset((char *) &tweak, 0, sizeof(tweak));
+    tweak.nelem = DICT_DB_NELM;
+    tweak.cachesize = DICT_DB_CACHE_SIZE;
+    return (dict_db_open(path, flags, DB_HASH, (void *) &tweak));
 }
 
 /* dict_btree_open - create association with data base */
 
 DICT   *dict_btree_open(const char *path, int flags)
 {
-    return (dict_db_open(path, flags, DB_BTREE));
+    BTREEINFO tweak;
+
+    memset((char *) &tweak, 0, sizeof(tweak));
+    tweak.cachesize = DICT_DB_CACHE_SIZE;
+
+    return (dict_db_open(path, flags, DB_BTREE, (void *) &tweak));
 }
 
 #endif
index 5d674f3c1350eb1bfe0ea3926415850520a6c9c2..d63150cbcde4c1d49c5231e4509e34877ecc23c9 100644 (file)
- /*
-  * The LDAP software is not bundled with IBM's public release. It will be
-  * made available as contributed software from http://www.postfix.org/
-  */
+/*++
+/* NAME
+/*     dict_ldap 3
+/* SUMMARY
+/*     dictionary manager interface to LDAP maps
+/* SYNOPSIS
+/*     #include <dict_ldap.h>
+/*
+/*     DICT    *dict_ldap_open(attribute, dummy)
+/*     const char *attribute;
+/*     int     dummy;
+/* DESCRIPTION
+/*     dict_ldap_open() makes LDAP user information accessible via
+/*     the generic dictionary operations described in dict_open(3).
+/*
+/*     Arguments:
+/* .IP ldapsource
+/*     The prefix which will be used to obtain configuration parameters
+/*     for this search. If it's 'ldapone', the configuration variables below 
+/*     would look like 'ldapone_server_host', 'ldapone_search_base', and so
+/*     on in main.cf.
+/* .IP dummy
+/*     Not used; this argument exists only for compatibility with
+/*     the dict_open(3) interface.
+/* .PP
+/*     Configuration parameters:
+/* .IP \fIldapsource_\fRserver_host
+/*     The host at which all LDAP queries are directed.
+/* .IP \fIldapsource_\fRserver_port
+/*     The port the LDAP server listens on.
+/* .IP \fIldapsource_\fRsearch_base
+/*     The LDAP search base, for example: \fIO=organization name, C=country\fR.
+/* .IP \fIldapsource_\fRtimeout
+/*     Deadline for LDAP open() and LDAP search() .
+/* .IP \fIldapsource_\fRquery_filter
+/*     The filter used to search for directory entries, for example
+/*     \fI(mailacceptinggeneralid=%s)\fR.
+/* .IP \fIldapsource_\fRresult_attribute
+/*     The attribute returned by the search, in which we expect to find
+/*     RFC822 addresses, for example \fImaildrop\fR.
+/* .IP \fIldapsource_\fRbind
+/*     Whether or not to bind to the server -- LDAP v3 implementations don't
+/*     require it, which saves some overhead.
+/* .IP \fIldapsource_\fRbind_dn
+/*     If you must bind to the server, do it with this distinguished name ...
+/* .IP \fIldapsource_\fRbind_pw
+/*     \&... and this password.
+/* BUGS
+/*     Of course not! :)
+/* SEE ALSO
+/*     dict(3) generic dictionary manager
+/* DIAGNOSTICS
+/*     Warnings: unable to connect to server, unable to bind to server.
+/* AUTHOR(S)
+/*     Prabhat K Singh
+/*     VSNL, Bombay, India.
+/*     prabhat@giasbm01.vsnl.net.in
+/*
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10532, USA
+/* 
+/*     John Hensley
+/*     Merit Network, Inc.
+/*     hensley@merit.edu
+/*
+/*--*/
+
+/* System library. */
+
 #include "sys_defs.h"
+
+#ifdef HAS_LDAP
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <lber.h>
+#include <ldap.h>
+
+/* Utility library. */
+
+#include "msg.h"
+#include "mymalloc.h"
+#include "vstring.h"
 #include "dict.h"
 #include "dict_ldap.h"
 
-#ifdef HAS_LDAP
-#error "This requires contributed software from http://www.postfix.org/"
+ /*
+  * Grr.. this module should sit in the global library, because it interacts
+  * with application-specific configuration parameters. I will have to
+  * generalize the manner in which new dictionary types can register
+  * themselves, including their configuration file parameters.
+  */
+
+/* 
+ * structure containing all the configuration parameters for a given
+ * LDAP source, plus its connection handle
+ */
+typedef struct {
+    DICT    dict;                        /* generic member */
+    char    *ldapsource;
+    char    *server_host;
+    int     server_port;
+    char    *search_base;
+    char    *query_filter;
+    char    *result_attribute;
+    int     bind;
+    char    *bind_dn;
+    char    *bind_pw;
+    int     timeout;
+    LDAP    *ld;
+} DICT_LDAP;
+
+ /*
+  * LDAP connection timeout support.
+  */
+static jmp_buf env;
+
+static void dict_ldap_timeout(int unused_sig)
+{
+    longjmp(env, 1);
+}
+
+/* dict_ldap_lookup - find database entry */
+
+static const char *dict_ldap_lookup(DICT *dict, const char *name)
+{
+    char   *myname = "dict_ldap_lookup";
+    DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
+    static VSTRING *result;
+    int LDAP_UNBIND = 0;
+    LDAPMessage *res = 0; 
+    LDAPMessage *entry = 0; 
+    struct timeval tv;
+    VSTRING *filter_buf = 0;
+    char  **attr_values;
+    long i = 0, j = 0;
+    int rc = 0;
+    void    (*saved_alarm) (int);
+
+    /*
+     * Initialize.
+     */
+    if (result == 0)
+        result = vstring_alloc(2);
+
+    vstring_strcpy(result,"");
+
+    if (msg_verbose)
+        msg_info("%s: In dict_ldap_lookup", myname);
+
+    if (dict_ldap->ld == 0) {
+        msg_warn("%s: no existing connection for ldapsource %s, reopening", 
+                 myname, dict_ldap->ldapsource);
+        if (msg_verbose)
+            msg_info("%s: connecting to server %s", myname, 
+                     dict_ldap->server_host);
+
+        if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR)
+            msg_fatal("%s: signal: %m", myname);
+
+        alarm(dict_ldap->timeout);
+        if (setjmp(env) == 0)
+            dict_ldap->ld = ldap_open(dict_ldap->server_host, 
+                           (int) dict_ldap->server_port);
+        alarm(0);
+
+        if (signal(SIGALRM, saved_alarm) == SIG_ERR)
+            msg_fatal("%s: signal: %m", myname);
+
+        if (msg_verbose)
+            msg_info("%s: after ldap_open", myname);
+
+        if (dict_ldap->ld == 0) {
+            msg_fatal("%s: Unable to contact LDAP server %s",
+                     myname, dict_ldap->server_host);
+        } else {
+            /*
+             * If this server requires us to bind, do so.
+             */
+            if (dict_ldap->bind) {
+                if (msg_verbose)
+                    msg_info("%s: about to bind: server %s, base %s", myname, 
+                         dict_ldap->server_host, dict_ldap->search_base);
+
+                rc = ldap_bind_s(dict_ldap->ld, dict_ldap->search_base, NULL, 
+                                 LDAP_AUTH_SIMPLE);
+                if (rc != LDAP_SUCCESS) {
+                    msg_fatal("%s: Unable to bind with search base %s at server %s (%d -- %s): ", myname, dict_ldap->search_base, dict_ldap->server_host, rc, ldap_err2string(rc));
+                } else {
+                    if (msg_verbose)
+                        msg_info("%s: Successful bind to server %s with search base %s(%d -- %s): ", myname, dict_ldap->search_base, dict_ldap->server_host, rc, ldap_err2string(rc));
+                }
+            }
+            if (msg_verbose)
+                msg_info("%s: cached connection handle for LDAP source %s",
+                         myname, dict_ldap->ldapsource);
+        }
+    }
+
+    /*
+     * Look for entries matching query_filter.
+     */
+    tv.tv_sec = dict_ldap->timeout;
+    tv.tv_usec = 0;
+    filter_buf = vstring_alloc(30);
+    vstring_sprintf(filter_buf, dict_ldap->query_filter, name);
+
+    if (msg_verbose)
+        msg_info("%s: searching with filter %s", myname, 
+                 vstring_str(filter_buf));
+
+    if ((rc=ldap_search_st(dict_ldap->ld, dict_ldap->search_base, 
+                           LDAP_SCOPE_SUBTREE,
+                           vstring_str(filter_buf), 
+                           0, 0, &tv, &res)) != LDAP_SUCCESS) {
+
+        msg_info("%s: right after search", myname);
+
+        msg_warn("%s: Unable to search base %s at server %s (%d -- %s): ", 
+                 myname, dict_ldap->search_base, dict_ldap->server_host, rc, 
+                 ldap_err2string(rc));
+        LDAP_UNBIND = 1;
+
+    } else {
+        /*
+         * Extract the requested result_attribute.
+         */
+        if (msg_verbose)
+            msg_info("%s: search completed", myname);
+
+        if ((entry = ldap_first_entry(dict_ldap->ld, res)) != 0) {
+            attr_values = ldap_get_values(dict_ldap->ld, entry, 
+                                          dict_ldap->result_attribute);
+            /*
+             * Append each returned address to the result list.
+             */
+            while (attr_values[i]) {
+                if (VSTRING_LEN(result) > 0)
+                    vstring_strcat(result, ",");
+                vstring_strcat(result, attr_values[i]);
+                i++;
+            }
+            ldap_value_free(attr_values);
+            if (msg_verbose)
+                msg_info("%s: search returned: %s", myname, vstring_str(result));
+        } else {
+            if (msg_verbose)
+                msg_info("%s: search returned nothing", myname);
+        }
+    }
+
+    /*
+     * Cleanup. Always return with dict_errno set when we were unable to
+     * perform the query.
+     */
+    if (res != 0)
+        ldap_msgfree(res);
+    else
+        dict_errno = 1;
+    if (LDAP_UNBIND == 1) {
+        /* 
+         * there was an LDAP problem; free the handle
+         */
+        ldap_unbind(dict_ldap->ld);
+        dict_ldap->ld = 0;
+        if (msg_verbose)
+            msg_info("%s: freed connection handle for LDAP source %s", 
+                     myname, dict_ldap->ldapsource);
+    }
+    if (filter_buf != 0)
+        vstring_free(filter_buf);
+    return (entry != 0 ? vstring_str(result) : 0);
+}
+
+/* dict_ldap_update - add or update database entry */
+
+static void dict_ldap_update(DICT *dict, const char *unused_name,
+                                     const char *unused_value)
+{
+    msg_fatal("dict_ldap_update: operation not implemented");
+}
+
+/* dict_ldap_close - disassociate from data base */
+
+static void dict_ldap_close(DICT *dict)
+{
+    char   *myname = "dict_ldap_close";
+    DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
+
+    if (dict_ldap->ld)
+        ldap_unbind(dict_ldap->ld);
+
+    myfree(dict_ldap->ldapsource);
+    myfree(dict_ldap->server_host);
+    myfree(dict_ldap->search_base);
+    myfree(dict_ldap->query_filter);
+    myfree(dict_ldap->result_attribute);
+    myfree(dict_ldap->bind_dn);
+    myfree(dict_ldap->bind_pw);
+    myfree((char *)dict_ldap);
+}
+
+/* dict_ldap_open - create association with data base */
+
+DICT   *dict_ldap_open(const char *ldapsource, int flags)
+{
+    char   *myname = "dict_ldap_open";
+    DICT_LDAP *dict_ldap;
+    VSTRING *config_param;
+    int rc = 0;
+    void    (*saved_alarm) (int);
+
+    dict_ldap = (DICT_LDAP *) mymalloc(sizeof(*dict_ldap));
+    dict_ldap->dict.lookup = dict_ldap_lookup;
+    dict_ldap->dict.update = dict_ldap_update;
+    dict_ldap->dict.close = dict_ldap_close;
+    dict_ldap->dict.fd = -1;
+
+    if (msg_verbose)
+        msg_info("%s: using LDAP source %s", myname, ldapsource);
+
+    dict_ldap->ldapsource = mystrdup(ldapsource);
+
+    config_param = vstring_alloc(15);
+    vstring_sprintf(config_param, "%s_server_host", ldapsource);
+
+    dict_ldap->server_host = 
+        mystrdup((char *)get_config_str(vstring_str(config_param), 
+                 "localhost",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->server_host);
+
+    /* get configured value of "ldapsource_server_port"; default to 
+    /* LDAP_PORT (389) */
+    vstring_sprintf(config_param, "%s_server_port", ldapsource);
+    dict_ldap->server_port = 
+        get_config_int(vstring_str(config_param),LDAP_PORT,0,0);
+    if (msg_verbose)
+        msg_info("%s: %s is %d", myname, vstring_str(config_param), 
+                 dict_ldap->server_port);
+
+    vstring_sprintf(config_param, "%s_search_base", ldapsource);
+    dict_ldap->search_base = 
+        mystrdup((char *)get_config_str(vstring_str(config_param),"",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->search_base);
+
+    /* get configured value of "ldapsource_timeout"; default to 10 */
+    vstring_sprintf(config_param, "%s_timeout", ldapsource);
+    dict_ldap->timeout = get_config_int(config_param,10,0,0);
+    if (msg_verbose)
+        msg_info("%s: %s is %d", myname, vstring_str(config_param), 
+                 dict_ldap->timeout);
+
+    vstring_sprintf(config_param, "%s_query_filter", ldapsource);
+    dict_ldap->query_filter = 
+        mystrdup((char *)get_config_str(vstring_str(config_param),
+                 "(mailacceptinggeneralid=%s)",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->query_filter);
+
+    vstring_sprintf(config_param, "%s_result_attribute", ldapsource);
+    dict_ldap->result_attribute = 
+        mystrdup((char *)get_config_str(vstring_str(config_param),
+                                        "maildrop",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->result_attribute);
+
+    /* get configured value of "ldapsource_bind"; default to true */
+    vstring_sprintf(config_param, "%s_bind", ldapsource);
+    dict_ldap->bind = get_config_bool(vstring_str(config_param), 1);
+    if (msg_verbose)
+        msg_info("%s: %s is %d", myname, vstring_str(config_param), 
+                 dict_ldap->bind);
+
+    /* get configured value of "ldapsource_bind_dn"; default to "" */
+    vstring_sprintf(config_param, "%s_bind_dn", ldapsource);
+    dict_ldap->bind_dn = 
+        mystrdup((char *)get_config_str(vstring_str(config_param),"",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->bind_dn);
+
+    /* get configured value of "ldapsource_bind_pw"; default to "" */
+    vstring_sprintf(config_param, "%s_bind_pw", ldapsource);
+    dict_ldap->bind_pw = 
+        mystrdup((char *)get_config_str(vstring_str(config_param),"",0,0));
+    if (msg_verbose)
+        msg_info("%s: %s is %s", myname, vstring_str(config_param), 
+                 dict_ldap->bind_pw);
+
+    /* 
+     * establish the connection to the LDAP server
+     */
+
+    if (msg_verbose)
+        msg_info("%s: connecting to server %s", myname, 
+                 dict_ldap->server_host);
+
+    if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR)
+        msg_fatal("%s: signal: %m", myname);
+
+    alarm(dict_ldap->timeout);
+    if (setjmp(env) == 0)
+        dict_ldap->ld = ldap_open(dict_ldap->server_host, 
+                       (int) dict_ldap->server_port);
+    alarm(0);
+
+    if (signal(SIGALRM, saved_alarm) == SIG_ERR)
+        msg_fatal("%s: signal: %m", myname);
+
+    if (msg_verbose)
+        msg_info("%s: after ldap_open", myname);
+
+    if (dict_ldap->ld == 0) {
+        msg_fatal("%s: Unable to contact LDAP server %s",
+                 myname, dict_ldap->server_host);
+    } else {
+        /*
+         * If this server requires us to bind, do so.
+         */
+        if (dict_ldap->bind) {
+            if (msg_verbose)
+                msg_info("%s: about to bind: server %s, base %s", myname, 
+                     dict_ldap->server_host, dict_ldap->search_base);
+
+            rc = ldap_bind_s(dict_ldap->ld, dict_ldap->search_base, NULL, 
+                             LDAP_AUTH_SIMPLE);
+            if (rc != LDAP_SUCCESS) {
+                msg_fatal("%s: Unable to bind with search base %s at server %s (%d -- %s): ", myname, dict_ldap->search_base, dict_ldap->server_host, rc, ldap_err2string(rc));
+            } else {
+                if (msg_verbose)
+                    msg_info("%s: Successful bind to server %s with search base %s(%d -- %s): ", myname, dict_ldap->search_base, dict_ldap->server_host, rc, ldap_err2string(rc));
+            }
+        }
+        if (msg_verbose)
+            msg_info("%s: cached connection handle for LDAP source %s",
+                     myname, dict_ldap->ldapsource);
+    }
+
+    return (&dict_ldap->dict);
+}
+
 #endif
index aaced3e7e596bbd4de4eb5d89f268878171b6fbb..8a88cdcef041be053e10bc020a484be3dcc11fc2 100644 (file)
@@ -1,4 +1,31 @@
+#ifndef _DICT_LDAP_H_INCLUDED_
+#define _DICT_LDAP_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_ldap 3h
+/* SUMMARY
+/*     dictionary manager interface to LDAP maps
+/* SYNOPSIS
+/*     #include <dict_ldap.h>
+/* DESCRIPTION
+/* .nf
+
  /*
-  * The LDAP software is not bundled with IBM's public release. It will be
-  * made available as contributed software from http://www.postfix.org/
+  * Utility library.
   */
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+extern DICT *dict_ldap_open(const char *, int);
+
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10532, USA
+/*--*/
+
+#endif
index f1dbbbb484f76c956bead3f60d8b5e74195338cf..b30defc8680c00120b3c2cbd08a17f28cff1cd0b 100644 (file)
@@ -50,7 +50,8 @@
 /*     NetInfo table. Only read access is supported.
 /* .IP ldap
 /*     LDAP ("light-weight" directory access protocol) database access.
-/*     The support is still incomplete.
+/* .IP pcre
+/*     PERL-compatible regular expressions.
 /* .PP
 /*     dict_open3() takes separate arguments for dictionary type and
 /*     name, but otherwise performs the same functions as dict_open().
 #include <msg.h>
 #include <dict.h>
 #include <dict_env.h>
+#include <dict_unix.h>
 #include <dict_dbm.h>
 #include <dict_db.h>
 #include <dict_nis.h>
 #include <dict_nisplus.h>
 #include <dict_ni.h>
 #include <dict_ldap.h>
+#include <dict_pcre.h>
 #include <stringops.h>
 #include <split_at.h>
 
@@ -113,6 +116,7 @@ typedef struct {
 
 static DICT_OPEN_INFO dict_open_info[] = {
     "environ", dict_env_open,
+    "unix", dict_unix_open,
 #ifdef HAS_DBM
     "dbm", dict_dbm_open,
 #endif
@@ -131,6 +135,9 @@ static DICT_OPEN_INFO dict_open_info[] = {
 #endif
 #ifdef HAS_LDAP
     "ldap", dict_ldap_open,
+#endif
+#ifdef HAS_PCRE
+    "pcre", dict_pcre_open,
 #endif
     0,
 };
diff --git a/postfix/util/dict_pcre.c b/postfix/util/dict_pcre.c
new file mode 100644 (file)
index 0000000..359a838
--- /dev/null
@@ -0,0 +1,382 @@
+/*++
+/* NAME
+/*     dict_pcre 3
+/* SUMMARY
+/*     dictionary manager interface to PCRE regular expression library
+/* SYNOPSIS
+/*     #include <dict_pcre.h>
+/*
+/*     DICT    *dict_pcre_open(name, flags)
+/*     const char *name;
+/*     int     flags;
+/* DESCRIPTION
+/*     dict_pcre_open() opens the named file and compiles the contained
+/*     regular expressions.
+/*
+/*      The lookup interface will match only user@domain form addresses.
+/* SEE ALSO
+/*     dict(3) generic dictionary manager
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Andrew McNamara
+/*     andrewm@connect.com.au
+/*     connect.com.au Pty. Ltd.
+/*     Level 3, 213 Miller St
+/*     North Sydney, NSW, Australia
+/*
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#include "sys_defs.h"
+
+#ifdef HAS_PCRE
+
+/* System library. */
+
+#include <stdio.h>                     /* sprintf() prototype */
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Utility library. */
+
+#include "mymalloc.h"
+#include "msg.h"
+#include "safe.h"
+#include "vstream.h"
+#include "vstring.h"
+#include "stringops.h"
+#include "readline.h"
+#include "dict.h"
+#include "dict_pcre.h"
+#include "mac_parse.h"
+
+/* PCRE library */
+
+#include "pcre.h"
+
+#define PCRE_MAX_CAPTURE       99      /* Max strings captured by regexp - */
+ /* essentially the max number of (..) */
+
+struct dict_pcre_list {
+    pcre   *pattern;                   /* The compiled pattern */
+    pcre_extra *hints;                 /* Hints to speed pattern execution */
+    char   *replace;                   /* Replacement string */
+    int     lineno;                    /* Source file line number */
+    struct dict_pcre_list *next;       /* Next regexp in dict */
+};
+
+typedef struct {
+    DICT    dict;                      /* generic members */
+    char   *map;                       /* map name */
+    int     flags;                     /* unused at the moment */
+    struct dict_pcre_list *head;
+} DICT_PCRE;
+
+static  dict_pcre_init = 0;            /* flag need to init pcre library */
+
+/*
+ *  dict_pcre_update - not supported
+ */
+static void dict_pcre_update(DICT *dict, const char *unused_name,
+                                    const char *unused_value)
+{
+    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
+
+    msg_fatal("dict_pcre_update: attempt to update regexp map %s",
+             dict_pcre->map);
+}
+
+/*
+ * Context for macro expansion callback.
+ */
+struct dict_pcre_context {
+    const char *dict_name;             /* source dict name */
+    int     lineno;                    /* source file line number */
+    VSTRING *buf;                      /* target string buffer */
+    const char *subject;               /* str against which we match */
+    int     offsets[PCRE_MAX_CAPTURE * 3];     /* Cut substrings */
+    int     matches;                   /* Count of cuts */
+};
+
+/*
+ * Macro expansion callback - replace $0-${99} with strings cut from
+ * matched string.
+ */
+static void dict_pcre_action(int type, VSTRING *buf, char *ptr)
+{
+    struct dict_pcre_context *ctxt = (struct dict_pcre_context *) ptr;
+    const char *pp;
+    int     n,
+            ret;
+
+    if (type == MAC_PARSE_VARNAME) {
+       n = atoi(vstring_str(buf));
+       ret = pcre_get_substring(ctxt->subject, ctxt->offsets, ctxt->matches,
+                                n, &pp);
+       if (ret < 0) {
+           if (ret == PCRE_ERROR_NOSUBSTRING)
+               msg_warn("regexp %s, line %d: replace index out of range",
+                        ctxt->dict_name, ctxt->lineno);
+           else
+               msg_warn("regexp %s, line %d: pcre_get_substring error: %d",
+                        ctxt->dict_name, ctxt->lineno, ret);
+           return;
+       }
+       vstring_strcat(ctxt->buf, pp);
+    } else
+       /* Straight text - duplicate with no substitution */
+       vstring_strcat(ctxt->buf, vstring_str(buf));
+}
+
+/*
+ * Look up regexp dict and perform string substitution on matched
+ * strings.
+ */
+static const char *dict_pcre_lookup(DICT *dict, const char *name)
+{
+    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
+    struct dict_pcre_list *pcre_list;
+    int     name_len = strlen(name);
+    struct dict_pcre_context ctxt;
+    static VSTRING *buf;
+    char   *at;
+
+/*    msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name );*/
+
+    /*
+     * XXX Require user@domain, to defeat partial address matching for smtp
+     * access control, canonical and virtual mappings, and to prevent regexps
+     * from being used as alias databases because one might inadvertantly
+     * copy "|command" or /file/name or :include: to the result.
+     */
+    if (name[0] == '@' || (at = strrchr(name, '@')) == 0 || at[1] == 0)
+       return (0);
+
+    /* Search for a matching expression */
+    for (pcre_list = dict_pcre->head; pcre_list; pcre_list = pcre_list->next) {
+       if (pcre_list->pattern) {
+           ctxt.matches = pcre_exec(pcre_list->pattern, pcre_list->hints,
+                    name, name_len, 0, ctxt.offsets, PCRE_MAX_CAPTURE * 3);
+           if (ctxt.matches != PCRE_ERROR_NOMATCH) {
+               if (ctxt.matches > 0)
+                   break;                      /* Got a match! */
+               else {
+                   /* An error */
+                   switch (ctxt.matches) {
+                   case 0:
+                       msg_warn("regexp map %s, line %d: too many (...)",
+                                dict_pcre->map, pcre_list->lineno);
+                       break;
+                   case PCRE_ERROR_NULL:
+                   case PCRE_ERROR_BADOPTION:
+                       msg_fatal("regexp map %s, line %d: bad args to re_exec",
+                                 dict_pcre->map, pcre_list->lineno);
+                       break;
+                   case PCRE_ERROR_BADMAGIC:
+                   case PCRE_ERROR_UNKNOWN_NODE:
+                       msg_fatal("regexp map %s, line %d: corrupt compiled regexp",
+                                 dict_pcre->map, pcre_list->lineno);
+                       break;
+                   default:
+                       msg_fatal("regexp map %s, line %d: unknown re_exec error: %d",
+                          dict_pcre->map, pcre_list->lineno, ctxt.matches);
+                       break;
+                   }
+                   return ((char *) 0);
+               }
+           }
+       }
+    }
+
+    /* If we've got a match, */
+    if (ctxt.matches > 0) {
+       /* Then perform substitution on replacement string */
+       if (buf == 0)
+           buf = vstring_alloc(10);
+       VSTRING_RESET(buf);
+       ctxt.buf = buf;
+       ctxt.subject = name;
+       ctxt.dict_name = dict_pcre->map;
+       ctxt.lineno = pcre_list->lineno;
+
+       mac_parse(pcre_list->replace, dict_pcre_action, (char *) &ctxt);
+
+       VSTRING_TERMINATE(buf);
+       return (vstring_str(buf));
+    }
+    return ((char *) 0);
+}
+
+/* dict_pcre_close - close pcre dictionary */
+
+static void dict_pcre_close(DICT *dict)
+{
+    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
+    struct dict_pcre_list *pcre_list;
+
+    for (pcre_list = dict_pcre->head; pcre_list; pcre_list = pcre_list->next) {
+       if (pcre_list->pattern)
+           myfree((char *) pcre_list->pattern);
+       if (pcre_list->hints)
+           myfree((char *) pcre_list->hints);
+       if (pcre_list->replace)
+           myfree((char *) pcre_list->replace);
+    }
+    myfree((char *) dict_pcre);
+}
+
+/*
+ * dict_pcre_open - load and compile a file containing regular expressions
+ */
+DICT   *dict_pcre_open(const char *map, int unused_flags)
+{
+    DICT_PCRE *dict_pcre;
+    VSTREAM *map_fp;
+    VSTRING *line_buffer;
+    struct dict_pcre_list *pcre_list = NULL,
+           *pl;
+    int     lineno = 0;
+    char   *regexp,
+           *p,
+            re_delimiter;
+    int     re_options;
+    pcre   *pattern;
+    pcre_extra *hints;
+    const char *error;
+    int     errptr;
+
+    line_buffer = vstring_alloc(100);
+
+    dict_pcre = (DICT_PCRE *) mymalloc(sizeof(*dict_pcre));
+    dict_pcre->dict.lookup = dict_pcre_lookup;
+    dict_pcre->dict.update = dict_pcre_update;
+    dict_pcre->dict.close = dict_pcre_close;
+    dict_pcre->dict.fd = -1;
+    dict_pcre->map = mystrdup(map);
+    dict_pcre->flags = 0;
+    dict_pcre->head = NULL;
+
+    if (dict_pcre_init == 0) {
+       pcre_malloc = (void *(*)(size_t)) mymalloc;
+       pcre_free = (void (*)(void *)) myfree;
+       dict_pcre_init = 1;
+    }
+    if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
+       msg_fatal("open %s: %m", map);
+    }
+    while (readline(line_buffer, map_fp, &lineno)) {
+
+       if (*vstring_str(line_buffer) == '#')   /* Skip comments */
+           continue;
+
+       if (*vstring_str(line_buffer) == 0)     /* Skip blank lines */
+           continue;
+
+       p = vstring_str(line_buffer);
+       re_delimiter = *p++;
+       regexp = p;
+
+       /* Search for second delimiter, handling backslash escape */
+       while (*p) {
+           if (*p == re_delimiter &&
+               (p > vstring_str(line_buffer) && *(p - 1) != '\\'))
+               break;
+           ++p;
+       }
+
+       if (!*p) {
+           msg_warn("%s, line %d: no closing regexp delimiter: %c",
+                    VSTREAM_PATH(map_fp), lineno, re_delimiter);
+           continue;
+       }
+       *p++ = '\0';                            /* Null term the regexp */
+
+       /* Now parse any regexp options */
+       re_options = PCRE_CASELESS;
+       while (*p && !ISSPACE(*p)) {
+           switch (*p) {
+           case 'i':
+               re_options ^= PCRE_CASELESS;
+               break;
+           case 'm':
+               re_options ^= PCRE_MULTILINE;
+               break;
+           case 's':
+               re_options ^= PCRE_DOTALL;
+               break;
+           case 'x':
+               re_options ^= PCRE_EXTENDED;
+               break;
+           case 'A':
+               re_options ^= PCRE_ANCHORED;
+               break;
+           case 'E':
+               re_options ^= PCRE_DOLLAR_ENDONLY;
+               break;
+           case 'U':
+               re_options ^= PCRE_UNGREEDY;
+               break;
+           case 'X':
+               re_options ^= PCRE_EXTRA;
+               break;
+           default:
+               msg_warn("%s, line %d: unknown regexp option '%c'",
+                        VSTREAM_PATH(map_fp), lineno, *p);
+           }
+           ++p;
+       }
+
+       while (*p && ISSPACE(*p))
+           ++p;
+
+       if (!*p) {
+           msg_warn("%s, line %d: no replacement text",
+                    VSTREAM_PATH(map_fp), lineno);
+           p = "";
+       }
+       /* Compile the patern */
+       pattern = pcre_compile(regexp, re_options, &error, &errptr, NULL);
+       if (pattern == NULL) {
+           msg_warn("%s, line %d: error in regex at offset %d: %s",
+                    VSTREAM_PATH(map_fp), lineno, errptr, error);
+           continue;
+       }
+       hints = pcre_study(pattern, 0, &error);
+       if (error != NULL) {
+           msg_warn("%s, line %d: error while studying regex: %s",
+                    VSTREAM_PATH(map_fp), lineno, error);
+           myfree((char *) pattern);
+           continue;
+       }
+       /* Add it to the list */
+       pl = (struct dict_pcre_list *) mymalloc(sizeof(struct dict_pcre_list));
+
+       /* Save the replacement string (if any) */
+       pl->replace = mystrdup(p);
+       pl->pattern = pattern;
+       pl->hints = hints;
+       pl->next = NULL;
+       pl->lineno = lineno;
+
+       if (pcre_list == NULL)
+           dict_pcre->head = pl;
+       else
+           pcre_list->next = pl;
+       pcre_list = pl;
+    }
+
+    vstring_free(line_buffer);
+    vstream_fclose(map_fp);
+
+    return (&dict_pcre->dict);
+}
+
+#endif                                 /* HAS_PCRE */
diff --git a/postfix/util/dict_pcre.h b/postfix/util/dict_pcre.h
new file mode 100644 (file)
index 0000000..2c6c118
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _DICT_PCRE_H_INCLUDED_
+#define _DICT_PCRE_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_pcre 3h
+/* SUMMARY
+/*     dictionary manager interface to PCRE regular expression library
+/* SYNOPSIS
+/*     #include <dict_pcre.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+extern DICT *dict_pcre_open(const char *, int);
+
+/* 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
+/*
+/*     Andrew McNamara
+/*     andrewm@connect.com.au
+/*     connect.com.au Pty. Ltd.
+/*     Level 3, 213 Miller St
+/*     North Sydney, NSW, Australia
+/*--*/
+
+#endif
diff --git a/postfix/util/dict_unix.c b/postfix/util/dict_unix.c
new file mode 100644 (file)
index 0000000..82f36b8
--- /dev/null
@@ -0,0 +1,125 @@
+/*++
+/* NAME
+/*     dict_unix 3
+/* SUMMARY
+/*     dictionary manager interface to UNIX tables
+/* SYNOPSIS
+/*     #include <dict_unix.h>
+/*
+/*     DICT    *dict_unix_open(map, dummy)
+/*     const char *map;
+/*     int     dummy;
+/* DESCRIPTION
+/*     dict_unix_open() makes the specified UNIX table accessible via
+/*     the generic dictionary operations described in dict_open(3).
+/*     The \fIdummy\fR argument is not used.
+/*
+/*     Known map names:
+/* .IP passwd.byname
+/*     The table is the UNIX password database. The key is a login name.
+/*     The result is a password file entry in passwd(5) format.
+/* SEE ALSO
+/*     dict(3) generic dictionary manager
+/* DIAGNOSTICS
+/*     Fatal errors: out of memory, unknown map name, attempt to update map.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include <string.h>
+#include <pwd.h>
+
+/* Utility library. */
+
+#include "msg.h"
+#include "mymalloc.h"
+#include "vstring.h"
+#include "dict.h"
+#include "dict_unix.h"
+
+/* Application-specific. */
+
+typedef struct {
+    DICT    dict;                      /* generic members */
+    char   *map;                       /* UNIX map name */
+} DICT_UNIX;
+
+/* dict_unix_getpwnam - find password table entry */
+
+static const char *dict_unix_getpwnam(DICT *unused_dict, const char *key)
+{
+    struct passwd *pwd;
+    static VSTRING *buf;
+
+    dict_errno = 0;
+
+    if ((pwd = getpwnam(key)) == 0) {
+       return (0);
+    } else {
+       if (buf == 0)
+           buf = vstring_alloc(10);
+       vstring_sprintf(buf, "%s:%s:%d:%d:%s:%s:%s",
+                    pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
+                       pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
+       return (vstring_str(buf));
+    }
+}
+
+/* dict_unix_update - add or update table entry */
+
+static void dict_unix_update(DICT *dict, const char *unused_name, const char *unused_value)
+{
+    DICT_UNIX *dict_unix = (DICT_UNIX *) dict;
+
+    msg_fatal("dict_unix_update: attempt to update map %s", dict_unix->map);
+}
+
+/* dict_unix_close - close UNIX map */
+
+static void dict_unix_close(DICT *dict)
+{
+    DICT_UNIX *dict_unix = (DICT_UNIX *) dict;
+
+    myfree(dict_unix->map);
+    myfree((char *) dict_unix);
+}
+
+/* dict_unix_open - open UNIX map */
+
+DICT   *dict_unix_open(const char *map, int unused_flags)
+{
+    DICT_UNIX *dict_unix;
+    struct dict_unix_lookup {
+       char   *name;
+       const char *(*lookup) (DICT *, const char *);
+    };
+    static struct dict_unix_lookup dict_unix_lookup[] = {
+       "passwd.byname", dict_unix_getpwnam,
+       0,
+    };
+    struct dict_unix_lookup *lp;
+
+    dict_unix = (DICT_UNIX *) mymalloc(sizeof(*dict_unix));
+    for (lp = dict_unix_lookup; /* void */ ; lp++) {
+       if (lp->name == 0)
+           msg_fatal("dict_unix_open: unknown map name: %s", map);
+       if (strcmp(map, lp->name) == 0)
+           break;
+    }
+    dict_unix->dict.lookup = lp->lookup;
+    dict_unix->dict.update = dict_unix_update;
+    dict_unix->dict.close = dict_unix_close;
+    dict_unix->dict.fd = -1;
+    dict_unix->map = mystrdup(map);
+    return (&dict_unix->dict);
+}
diff --git a/postfix/util/dict_unix.h b/postfix/util/dict_unix.h
new file mode 100644 (file)
index 0000000..df8dc64
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _DIST_UNIX_H_INCLUDED_
+#define _DIST_UNIX_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_unix 3h
+/* SUMMARY
+/*     dictionary manager interface to UNIX maps
+/* SYNOPSIS
+/*     #include <dict_unix.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+extern DICT *dict_unix_open(const char *, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
index aaf423ba177409765f33df7c19abb5a259c02215..dc61e97c0c556f4ecb026584d60201c5c43c2db3 100644 (file)
@@ -12,7 +12,7 @@
 /*     int     delay;
 /*
 /*     time_t  event_request_timer(callback, context, delay)
-/*     void    (*callback)(char *context);
+/*     void    (*callback)(int event, char *context);
 /*     char    *context;
 /*     int     delay;
 /*
@@ -57,6 +57,7 @@
 /*     be called with the specified context argument after \fIdelay\fR
 /*     seconds, or as soon as possible thereafter. The delay should
 /*     not be negative.
+/*     The event argument is equal to EVENT_TIME.
 /*     Only one timer request can be active per (callback, context) pair.
 /*     Calling event_request_timer() with an existing (callback, context)
 /*     pair does not schedule a new event, but updates the moment of
@@ -534,7 +535,7 @@ void    event_loop(int delay)
        if (msg_verbose > 2)
            msg_info("%s: timer 0x%lx 0x%lx", myname,
                     (long) timer->callback, (long) timer->context);
-       timer->callback(timer->context);        /* then this */
+       timer->callback(EVENT_TIME, timer->context);    /* then this */
        myfree((char *) timer);
     }
 
index f3f6208d73e75d37d31f008d47af5ebb2c594e06..bc39b4787c4d74e041ef0222faaf68ec4e3c2b11 100644 (file)
@@ -20,7 +20,7 @@
   * External interface.
   */
 typedef void (*EVENT_NOTIFY_RDWR) (int, char *);
-typedef void (*EVENT_NOTIFY_TIME) (char *);
+typedef void (*EVENT_NOTIFY_TIME) (int, char *);
 
 extern time_t event_time(void);
 extern void event_enable_read(int, EVENT_NOTIFY_RDWR, char *);
@@ -36,6 +36,7 @@ extern void event_loop(int);
 #define EVENT_READ     (1<<0)          /* read event */
 #define EVENT_WRITE    (1<<1)          /* write event */
 #define EVENT_XCPT     (1<<2)          /* exception */
+#define EVENT_TIME     (1<<3)          /* timer event */
 
 #define EVENT_ERROR    EVENT_XCPT
 
index 2e67d91873f10c47a424c5c06baf287eaac56098..299d0c614a546ac944ed1cac82de4e669d452853 100644 (file)
 /*     HTABLE  *table;
 /*     void    (*free_fn)(char *);
 /*
-/*     void    htable_walk(table, action)
+/*     void    htable_walk(table, action, ptr)
 /*     HTABLE  *table;
-/*     void    (*action)(HTABLE_INFO *);
+/*     void    (*action)(HTABLE_INFO *, char *ptr);
+/*     char    *ptr;
 /*
 /*     HTABLE_INFO *htable_list(table)
 /*     HTABLE  *table;
@@ -78,7 +79,8 @@
 /*     with the entry.
 /*
 /*     htable_walk() invokes the action function for each table entry, with
-/*     a pointer to the entry as its argument.
+/*     a pointer to the entry as its argument. The ptr argument is passed
+/*     on to the action function.
 /*
 /*     htable_list() returns a null-terminated list of pointers to
 /*     all elements in the named table. The list should be passed to
@@ -296,8 +298,8 @@ void    htable_free(HTABLE *table, void (*free_fn) (char *))
 
 /* htable_walk - iterate over hash table */
 
-void    htable_walk(HTABLE *table, void (*action) (HTABLE_INFO *))
-{
+void    htable_walk(HTABLE *table, void (*action) (HTABLE_INFO *, char *),
+                           char *ptr) {
     if (table) {
        unsigned i = table->size;
        HTABLE_INFO **h = table->data;
@@ -305,7 +307,7 @@ void    htable_walk(HTABLE *table, void (*action) (HTABLE_INFO *))
 
        while (i-- > 0)
            for (ht = *h++; ht; ht = ht->next)
-               (*action) (ht);
+               (*action) (ht, ptr);
     }
 }
 
index 8a9bbfd3b983336f9a9023b16cf2c5442fde76bc..72eaa98f1a62a3ced4717d0d2cb42ba2b73e6706 100644 (file)
@@ -34,7 +34,7 @@ extern HTABLE_INFO *htable_locate(HTABLE *, const char *);
 extern char *htable_find(HTABLE *, const char *);
 extern void htable_delete(HTABLE *, const char *, void (*) (char *));
 extern void htable_free(HTABLE *, void (*) (char *));
-extern void htable_walk(HTABLE *, void (*) (HTABLE_INFO *));
+extern void htable_walk(HTABLE *, void (*) (HTABLE_INFO *, char *), char *);
 extern HTABLE_INFO **htable_list(HTABLE *);
 
 /* LICENSE
index b13b5eba66ac1c059eccbb98bb5eab05391d8753..1b5680bde691042f36cda8acab8519029ed23d19 100644 (file)
 /*     char    *scan_dir_path(scan)
 /*     SCAN_DIR *scan;
 /*
+/*     void    scan_push(scan, entry)
+/*     SCAN_DIR *scan;
+/*     const char *entry;
+/*
+/*     SCAN_DIR *scan_pop(scan)
+/*     SCAN_DIR *scan;
+/*
 /*     SCAN_DIR *scan_dir_close(scan)
 /*     SCAN_DIR *scan;
 /* DESCRIPTION
 /*     scan_dir_open() opens the named directory and
 /*     returns a handle for subsequent use.
 /*
-/*     scan_dir_close() closes the directory and cleans up
+/*     scan_dir_close() terminates the directory scan, cleans up
 /*     and returns a null pointer.
 /*
-/*     scan_dir_next() returns the next filename in the specified
+/*     scan_dir_next() returns the next requested object in the specified
 /*     directory. It skips the "." and ".." entries.
 /*
 /*     scan_dir_path() returns the name of the directory being scanned.
+/*
+/*     scan_dir_push() causes the specified directory scan to enter the
+/*     named subdirectory.
+/*
+/*     scan_dir_pop() leaves the directory being scanned and returns
+/*     to the previous one. The result is the argument, null if no
+/*     previous directory information is available.
 /* DIAGNOSTICS
 /*     All errors are fatal.
 /* LICENSE
 #include <dirent.h>
 #include <string.h>
 
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-#define dirent direct
-#define NAMLEN(dirent) (dirent)->d_namlen
-#ifdef HAVE_SYS_NDIR_H
-#include <sys/ndir.h>
-#endif
-#ifdef HAVE_SYS_DIR_H
-#include <sys/dir.h>
-#endif
-#ifdef HAVE_NDIR_H
-#include <ndir.h>
-#endif
-#endif
-
 /* Utility library. */
 
 #include "msg.h"
 #include "mymalloc.h"
+#include "stringops.h"
+#include "vstring.h"
 #include "scan_dir.h"
 
  /*
-  * Opaque structure, so we don't have to expose the user to the above #ifdef
-  * spaghetti.
+  * The interface is based on an opaque structure, so we don't have to expose
+  * the user to the guts. Subdirectory info sits in front of parent directory
+  * info: a simple last-in, first-out list.
   */
+typedef struct SCAN_INFO SCAN_INFO;
+
+struct SCAN_INFO {
+    char   *path;                      /* directory name */
+    DIR    *dir;                       /* directory structure */
+    SCAN_INFO *parent;                 /* linkage */
+};
 struct SCAN_DIR {
-    char   *path;
-    DIR    *dir;
+    SCAN_INFO *current;                        /* current scan */
 };
 
+#define SCAN_DIR_PATH(scan)    (scan->current->path)
+#define STR(x)                 vstring_str(x)
+
 /* scan_dir_path - return the path of the directory being read.  */
 
 char   *scan_dir_path(SCAN_DIR *scan)
 {
-    return scan->path;
+    return (SCAN_DIR_PATH(scan));
+}
+
+/* scan_dir_push - enter directory */
+
+void    scan_dir_push(SCAN_DIR *scan, const char *path)
+{
+    char   *myname = "scan_dir_push";
+    SCAN_INFO *info;
+
+    info = (SCAN_INFO *) mymalloc(sizeof(*info));
+    if (scan->current)
+       info->path = concatenate(SCAN_DIR_PATH(scan), "/", path, (char *) 0);
+    else
+       info->path = mystrdup(path);
+    if ((info->dir = opendir(info->path)) == 0)
+       msg_fatal("%s: open directory %s: %m", myname, info->path);
+    if (msg_verbose > 1)
+       msg_info("%s: open %s", myname, info->path);
+    info->parent = scan->current;
+    scan->current = info;
+}
+
+/* scan_dir_pop - leave directory */
+
+SCAN_DIR *scan_dir_pop(SCAN_DIR *scan)
+{
+    char   *myname = "scan_dir_pop";
+    SCAN_INFO *info = scan->current;
+    SCAN_INFO *parent;
+
+    if (info == 0)
+       return (0);
+    parent = info->parent;
+    if (closedir(info->dir))
+       msg_fatal("%s: close directory %s: %m", myname, info->path);
+    if (msg_verbose > 1)
+       msg_info("%s: close %s", myname, info->path);
+    myfree(info->path);
+    myfree((char *) info);
+    scan->current = parent;
+    return (parent ? scan : 0);
 }
 
 /* scan_dir_open - start directory scan */
@@ -98,25 +148,32 @@ SCAN_DIR *scan_dir_open(const char *path)
     SCAN_DIR *scan;
 
     scan = (SCAN_DIR *) mymalloc(sizeof(*scan));
-    if ((scan->dir = opendir(path)) == 0)
-       msg_fatal("open directory %s: %m", path);
-    if (msg_verbose > 1)
-       msg_info("scan_dir_open: %s", path);
-    scan->path = mystrdup(path);
+    scan->current = 0;
+    scan_dir_push(scan, path);
     return (scan);
 }
 
+/* scan_dir_next - find next entry */
+
 char   *scan_dir_next(SCAN_DIR *scan)
 {
+    char   *myname = "scan_dir_next";
+    SCAN_INFO *info = scan->current;
     struct dirent *dp;
 
-#define STRNE(x,y)     (strcmp((x),(y)) != 0)
-
-    while ((dp = readdir(scan->dir)) != 0) {
-       if (STRNE(dp->d_name, ".") && STRNE(dp->d_name, "..")) {
-           if (msg_verbose > 1)
-               msg_info("scan_dir_next: %s", dp->d_name);
-           return (dp->d_name);
+#define STREQ(x,y)     (strcmp((x),(y)) == 0)
+
+    if (info) {
+       while ((dp = readdir(info->dir)) != 0) {
+           if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) {
+               if (msg_verbose > 1)
+                   msg_info("%s: skip %s", myname, dp->d_name);
+               continue;
+           } else {
+               if (msg_verbose > 1)
+                   msg_info("%s: found %s", myname, dp->d_name);
+               return (dp->d_name);
+           }
        }
     }
     return (0);
@@ -126,11 +183,8 @@ char   *scan_dir_next(SCAN_DIR *scan)
 
 SCAN_DIR *scan_dir_close(SCAN_DIR *scan)
 {
-    if (closedir(scan->dir))
-       msg_fatal("close directory %s: %m", scan->path);
-    if (msg_verbose > 1)
-       msg_info("scan_dir_close: %s", scan->path);
-    myfree(scan->path);
+    while (scan->current)
+       scan_dir_pop(scan);
     myfree((char *) scan);
     return (0);
 }
index cc7e5538cc5c71e70d5473c8d98368b34f2e5663..8f3bf8b98bc05ce14d7bf343f9fccff9f5522756 100644 (file)
 /* DESCRIPTION
 /* .nf
 
- /*
-  * System library.
-  */
-#include <dirent.h>
-
  /*
   * The directory scanner interface.
   */
@@ -24,6 +19,8 @@ typedef struct SCAN_DIR SCAN_DIR;
 extern SCAN_DIR *scan_dir_open(const char *);
 extern char *scan_dir_next(SCAN_DIR *);
 extern char *scan_dir_path(SCAN_DIR *);
+extern void scan_dir_push(SCAN_DIR *, const char *);
+extern SCAN_DIR *scan_dir_pop(SCAN_DIR *);
 extern SCAN_DIR *scan_dir_close(SCAN_DIR *);
 
 /* LICENSE
diff --git a/postfix/util/select_bug.c b/postfix/util/select_bug.c
new file mode 100644 (file)
index 0000000..ff5f362
--- /dev/null
@@ -0,0 +1,93 @@
+/*++
+/* NAME
+/*     select_bug 1
+/* SUMMARY
+/*     select test program
+/* SYNOPSIS
+/*     select_bug
+/* DESCRIPTION
+/*     select_bug forks child processes that perform select()
+/*     on a shared socket, and sees if a wakeup affects other
+/*     processes selecting on a different socket or stdin.
+/* DIAGNOSTICS
+/*     Problems are reported to the standard error stream.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>                    /* bzero() prototype for 44BSD */
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+
+static pid_t fork_and_read_select(const char *what, int delay, int fd)
+{
+    struct timeval tv;
+    pid_t   pid;
+    fd_set  readfds;
+
+    switch (pid = fork()) {
+    case -1:
+       msg_fatal("fork: %m");
+    case 0:
+       tv.tv_sec = delay;
+       tv.tv_usec = 0;
+       FD_ZERO(&readfds);
+       FD_SET(fd, &readfds);
+       switch (select(fd + 1, &readfds, (fd_set *) 0, &readfds, &tv)) {
+       case -1:
+           msg_fatal("select: %m");
+       case 0:
+           msg_info("%s select timed out", what);
+           exit(0);
+       default:
+           msg_info("%s select wakeup", what);
+           exit(0);
+       }
+    default:
+       return (pid);
+    }
+}
+
+main(int argc, char **argv)
+{
+    int     pair1[2];
+    int     pair2[2];
+
+    msg_vstream_init(argv[0], VSTREAM_ERR);
+
+#define DELAY 1
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair1) < 0)
+       msg_fatal("socketpair: %m");
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair2) < 0)
+       msg_fatal("socketpair: %m");
+
+    vstream_printf("Doing multiple select on socket1, then write to it...\n");
+    vstream_fflush(VSTREAM_OUT);
+    fork_and_read_select("socket1", DELAY, pair1[0]);  /* one */
+    fork_and_read_select("socket1", DELAY, pair1[0]);  /* two */
+    fork_and_read_select("socket2", DELAY, pair2[0]);
+    fork_and_read_select("stdin", DELAY, 0);
+    if (write(pair1[1], "", 1) != 1)
+       msg_fatal("write: %m");
+    while (wait((int *) 0) >= 0)
+        /* void */ ;
+}
index e91483080d025993dfde7338c789a98f4ce0dde5..21b0e0151f0c74571feda9845f3734b2fe31c4ef 100644 (file)
@@ -19,7 +19,7 @@
   * directory. Adding support for a new system type means updating the
   * makedefs script, and adding a section below for the new system.
   */
-#if defined(FREEBSD2) || defined(FREEBSD3) \
+#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
     || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
     || defined(OPENBSD2) || defined(NETBSD1)
 #define SUPPORTED
@@ -179,6 +179,32 @@ extern int opterr;
 #define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
 #endif
 
+#ifdef UW21              /* UnixWare 2.1.x */                        
+#define SUPPORTED                                               
+#include <sys/types.h>                                          
+#define _PATH_MAILDIR   "/var/mail"                             
+#define _PATH_BSHELL    "/bin/sh"                               
+#define _PATH_DEFPATH   "/usr/bin:/usr/ucb"                     
+#define _PATH_STDPATH   "/usr/bin:/usr/sbin:/usr/ucb"           
+#define MISSING_SETENV                                          
+#define USE_FCNTL_LOCK                                          
+#define USE_DOT_LOCK                                            
+#define HAS_FSYNC                                               
+#define HAS_DBM
+#define DEF_DB_TYPE     "dbm"                                   
+#define ALIAS_DB_MAP    "dbm:/etc/mail/aliases"                 
+/* Uncomment the following line if you have NIS package installed
+#define HAS_NIS */
+#define USE_SYS_SOCKIO_H                                        
+#define GETTIMEOFDAY(t) gettimeofday(t,NULL)   
+#define ROOT_PATH       "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb"
+#define FIONREAD_IN_SYS_FILIO_H                                 
+#define DBM_NO_TRAILING_NULL                                    
+#define USE_STATVFS                                             
+#define STATVFS_IN_SYS_STATVFS_H                                
+#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
+#endif
+
 #ifdef AIX4
 #define SUPPORTED
 #include <sys/types.h>
index 25d1f6c564c0d18556723963dc00c4c09d698e45..7fff779c37889ec60461b8f04d0b3cf0dd93b90c 100644 (file)
@@ -8,13 +8,22 @@
 /*
 /*     int     valid_hostname(name)
 /*     const char *name;
+/*
+/*     int     valid_hostaddr(addr)
+/*     const char *addr;
 /* DESCRIPTION
 /*     valid_hostname() scrutinizes a hostname: the name should be no
 /*     longer than VALID_HOSTNAME_LEN characters, should contain only
 /*     letters, digits, dots and hyphens, no adjacent dots and hyphens,
-/*     no leading or trailing dots or hyphens.
+/*     no leading or trailing dots or hyphens, no labels longer than
+/*     VALID_LABEL_LEN characters, and no numeric top-level domain.
+/*
+/*     valid_hostaddr() requirs that the input is a valid string
+/*     representation of an internet network address.
+/* DIAGNOSTICS
+/*     Both functions return zero if they disagree with the input.
 /* SEE ALSO
-/*     RFC 952, 1123
+/*     RFC 952, 1123, RFC 1035
 /* LICENSE
 /* .ad
 /* .fi
 
 int     valid_hostname(const char *name)
 {
+    char   *myname = "valid_hostname";
     const char *cp;
-    char   *str;
+    int     label_length = 0;
+    int     label_count = 0;
+    int     non_numeric = 0;
     int     ch;
-    int     len;
-    int     bad_val = 0;
-    int     adjacent = 0;
-
-#define DELIMITER(c) (c == '.' || c == '-')
 
     /*
      * Trivial cases first.
      */
     if (*name == 0) {
-       msg_warn("valid_hostname: empty hostname");
+       msg_warn("%s: empty hostname", myname);
        return (0);
     }
 
     /*
-     * Find bad characters. Find adjacent delimiters.
+     * Find bad characters or label lengths. Find adjacent delimiters.
      */
-    for (cp = name; (ch = *cp) != 0; cp++) {
-       if (DELIMITER(ch)) {
-           if (DELIMITER(cp[1]))
-               adjacent = 1;
-       } else if (!ISALNUM(ch) && ch != '_') { /* grr.. */
-           if (bad_val == 0)
-               bad_val = ch;
+    for (cp = name; (ch = *(unsigned char *) cp) != 0; cp++) {
+       if (ISALNUM(ch) || ch == '_') {         /* grr.. */
+           if (label_length == 0)
+               label_count++;
+           label_length++;
+           if (label_length > VALID_LABEL_LEN) {
+               msg_warn("%s: hostname label too long: %.100s", myname, name);
+               return (0);
+           }
+           if (!ISDIGIT(ch))
+               non_numeric = 1;
+       } else if (ch == '.' || ch == '-') {
+           if (label_length == 0 || cp[1] == 0) {
+               msg_warn("%s: misplaced delimiter: %.100s", myname, name);
+               return (0);
+           }
+           label_length = 0;
+       } else {
+           msg_warn("%s: invalid character %d(decimal): %.100s",
+                    myname, ch, name);
+           return (0);
        }
     }
 
-    /*
-     * Before printing the name, validate its length.
-     */
-    if ((len = strlen(name)) > VALID_HOSTNAME_LEN) {
-       str = printable(mystrdup(name), '?');
-       msg_warn("valid_hostname: bad length %d for %.100s...", len, str);
-       myfree(str);
+    if (non_numeric == 0) {
+       msg_warn("%s: numeric hostname: %.100s", myname, name);
+       /* NOT: return (0); this confuses users of the DNS client */
+    }
+    if (cp - name > VALID_HOSTNAME_LEN) {
+       msg_warn("%s: bad length %d for %.100s...", myname, cp - name, name);
        return (0);
     }
+    return (1);
+}
+
+/* valid_hostaddr - test dotted quad string for correctness */
+
+int     valid_hostaddr(const char *addr)
+{
+    const char *cp;
+    char   *myname = "valid_hostaddr";
+    int     in_byte = 0;
+    int     byte_count = 0;
+    int     byte_val = 0;
+    int     ch;
+
+#define BYTES_NEEDED   4
 
     /*
-     * Report bad characters.
+     * Trivial cases first.
      */
-    if (bad_val) {
-       str = printable(mystrdup(name), '?');
-       msg_warn("valid_hostname: invalid character %d(decimal) in %s",
-                bad_val, str);
-       myfree(str);
+    if (*addr == 0) {
+       msg_warn("%s: empty address", myname);
        return (0);
     }
 
     /*
-     * Misplaced delimiters.
+     * Scary code to avoid sscanf() overflow nasties.
      */
-    if (DELIMITER(name[0]) || adjacent || DELIMITER(name[len - 1])) {
-       msg_warn("valid_hostname: misplaced delimiter in %s", name);
+    for (cp = addr; (ch = *(unsigned const char *) cp) != 0; cp++) {
+       if (ISDIGIT(ch)) {
+           if (in_byte == 0) {
+               in_byte = 1;
+               byte_val = 0;
+               byte_count++;
+           }
+           byte_val *= 10;
+           byte_val += ch - '0';
+           if (byte_val > 255) {
+               msg_warn("%s: invalid octet value: %.100s", myname, addr);
+               return (0);
+           }
+       } else if (ch == '.') {
+           if (in_byte == 0 || cp[1] == 0) {
+               msg_warn("%s: misplaced dot: %.100s", myname, addr);
+               return (0);
+           }
+           if ((byte_count == 1 && byte_val == 0)) {
+               msg_warn("%s: bad initial octet value: %.100s", myname, addr);
+               return (0);
+           }
+           in_byte = 0;
+       } else {
+           msg_warn("%s: invalid character %d(decimal): %.100s",
+                    myname, ch, addr);
+           return (0);
+       }
+    }
+
+    if (byte_count != BYTES_NEEDED) {
+       msg_warn("%s: invalid octet count: %.100s", myname, addr);
        return (0);
     }
     return (1);
@@ -124,8 +186,11 @@ int     main(int unused_argc, char **argv)
     msg_vstream_init(argv[0], VSTREAM_ERR);
     msg_verbose = 1;
 
-    while (vstring_fgets_nonl(buffer, VSTREAM_IN))
+    while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
+       msg_info("testing: \"%s\"", vstring_str(buffer));
        valid_hostname(vstring_str(buffer));
+       valid_hostaddr(vstring_str(buffer));
+    }
     exit(0);
 }
 
index 53f5eb99f6606c00f96fd6c78ebcf64794dffd08..69db140567069a3886d1b9536cf2e2a271481515 100644 (file)
 
  /* External interface */
 
-#define VALID_HOSTNAME_LEN     256
+#define VALID_HOSTNAME_LEN     255     /* RFC 1035 */
+#define VALID_LABEL_LEN                63      /* RFC 1035 */
 
 extern int valid_hostname(const char *);
+extern int valid_hostaddr(const char *);
 
 /* LICENSE
 /* .ad
diff --git a/postfix/util/valid_hostname.in b/postfix/util/valid_hostname.in
new file mode 100644 (file)
index 0000000..78a6f24
--- /dev/null
@@ -0,0 +1,28 @@
+123456789012345678901234567890123456789012345678901234567890123
+1234567890123456789012345678901234567890123456789012345678901234
+a.123456789012345678901234567890123456789012345678901234567890123.b
+a.1234567890123456789012345678901234567890123456789012345678901234.b
+1.2.3.4
+321.255.255.255
+0.0.0.0
+255.255.255.255
+0.255.255.255
+1.2.3.321
+1.2.3
+1.2.3.4.5
+1..2.3.4
+.1.2.3.4
+1.2.3.4.5.
+1
+.
+
+321
+f
+f.2.3.4
+1f.2.3.4
+f1.2.3.4
+1.2f.3.4
+1.f2.3.4
+1.2.3.4f
+1.2.3.f4
+1.2.3.f
diff --git a/postfix/util/valid_hostname.ref b/postfix/util/valid_hostname.ref
new file mode 100644 (file)
index 0000000..44be99f
--- /dev/null
@@ -0,0 +1,72 @@
+./valid_hostname: testing: "123456789012345678901234567890123456789012345678901234567890123"
+./valid_hostname: warning: valid_hostname: numeric hostname: 123456789012345678901234567890123456789012345678901234567890123
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 123456789012345678901234567890123456789012345678901234567890123
+./valid_hostname: testing: "1234567890123456789012345678901234567890123456789012345678901234"
+./valid_hostname: warning: valid_hostname: hostname label too long: 1234567890123456789012345678901234567890123456789012345678901234
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 1234567890123456789012345678901234567890123456789012345678901234
+./valid_hostname: testing: "a.123456789012345678901234567890123456789012345678901234567890123.b"
+./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.123456789012345678901234567890123456789012345678901234567890123.b
+./valid_hostname: testing: "a.1234567890123456789012345678901234567890123456789012345678901234.b"
+./valid_hostname: warning: valid_hostname: hostname label too long: a.1234567890123456789012345678901234567890123456789012345678901234.b
+./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.1234567890123456789012345678901234567890123456789012345678901234.b
+./valid_hostname: testing: "1.2.3.4"
+./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4
+./valid_hostname: testing: "321.255.255.255"
+./valid_hostname: warning: valid_hostname: numeric hostname: 321.255.255.255
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 321.255.255.255
+./valid_hostname: testing: "0.0.0.0"
+./valid_hostname: warning: valid_hostname: numeric hostname: 0.0.0.0
+./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.0.0.0
+./valid_hostname: testing: "255.255.255.255"
+./valid_hostname: warning: valid_hostname: numeric hostname: 255.255.255.255
+./valid_hostname: testing: "0.255.255.255"
+./valid_hostname: warning: valid_hostname: numeric hostname: 0.255.255.255
+./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
+./valid_hostname: testing: "1.2.3.321"
+./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.321
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 1.2.3.321
+./valid_hostname: testing: "1.2.3"
+./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3
+./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3
+./valid_hostname: testing: "1.2.3.4.5"
+./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4.5
+./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
+./valid_hostname: testing: "1..2.3.4"
+./valid_hostname: warning: valid_hostname: misplaced delimiter: 1..2.3.4
+./valid_hostname: warning: valid_hostaddr: misplaced dot: 1..2.3.4
+./valid_hostname: testing: ".1.2.3.4"
+./valid_hostname: warning: valid_hostname: misplaced delimiter: .1.2.3.4
+./valid_hostname: warning: valid_hostaddr: misplaced dot: .1.2.3.4
+./valid_hostname: testing: "1.2.3.4.5."
+./valid_hostname: warning: valid_hostname: misplaced delimiter: 1.2.3.4.5.
+./valid_hostname: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
+./valid_hostname: testing: "1"
+./valid_hostname: warning: valid_hostname: numeric hostname: 1
+./valid_hostname: warning: valid_hostaddr: invalid octet count: 1
+./valid_hostname: testing: "."
+./valid_hostname: warning: valid_hostname: misplaced delimiter: .
+./valid_hostname: warning: valid_hostaddr: misplaced dot: .
+./valid_hostname: testing: ""
+./valid_hostname: warning: valid_hostname: empty hostname
+./valid_hostname: warning: valid_hostaddr: empty address
+./valid_hostname: testing: "321"
+./valid_hostname: warning: valid_hostname: numeric hostname: 321
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 321
+./valid_hostname: testing: "f"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f
+./valid_hostname: testing: "f.2.3.4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f.2.3.4
+./valid_hostname: testing: "1f.2.3.4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1f.2.3.4
+./valid_hostname: testing: "f1.2.3.4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f1.2.3.4
+./valid_hostname: testing: "1.2f.3.4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2f.3.4
+./valid_hostname: testing: "1.f2.3.4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.f2.3.4
+./valid_hostname: testing: "1.2.3.4f"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.4f
+./valid_hostname: testing: "1.2.3.f4"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f4
+./valid_hostname: testing: "1.2.3.f"
+./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f
index 4014e1875a315ee3919a6b826fa2181ee50b2e4c..f6da5dbe749d0bd92f481a4c6c70bc6d653d6a22 100644 (file)
@@ -87,6 +87,9 @@
 /*     char    *vstream_vfprintf(vp, format, ap)
 /*     char    *format;
 /*     va_list *ap;
+/*
+/*     int     vstream_peek(stream)
+/*     VSTREAM *stream;
 /* DESCRIPTION
 /*     The \fIvstream\fR module implements light-weight buffered I/O
 /*     similar to the standard I/O routines.
 /*     The argument specifies the file descriptor to be used for writing.
 /*     This feature is limited to double-buffered streams, and makes the
 /*     stream non-seekable.
+/* .IP "VSTREAM_CTL_WAITPID_FN (int (*)(pid_t, WAIT_STATUS_T *, int))"
+/*     A pointer to function that behaves like waitpid(). This information
+/*     is used by the vstream_pclose() routine.
 /* .PP
 /*     vstream_fileno() gives access to the file handle associated with
 /*     a buffered stream. With streams that have separate read/write
 /*
 /*     vstream_vfprintf() provides an alternate interface
 /*     for formatting an argument list according to a format string.
+/*
+/*     vstream_peek() returns the number of characters that can be
+/*     read from the named stream without refilling the read buffer.
 /* DIAGNOSTICS
 /*     Panics: interface violations. Fatal errors: out of memory.
 /* SEE ALSO
@@ -833,6 +842,8 @@ VSTREAM *vstream_fdopen(int fd, int flags)
     vstream_buf_init(&stream->buf, flags);
     stream->offset = 0;
     stream->path = 0;
+    stream->pid = 0;
+    stream->waitpid_fn = 0;
     return (stream);
 }
 
@@ -869,6 +880,8 @@ int     vstream_fclose(VSTREAM *stream)
 {
     int     err;
 
+    if (stream->pid != 0)
+       msg_panic("vstream_fclose: stream has process");
     if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0)
        vstream_fflush(stream);
     err = vstream_ferror(stream);
@@ -971,6 +984,9 @@ void    vstream_control(VSTREAM *stream, int name,...)
            stream->write_fd = va_arg(ap, int);
            stream->buf.flags |= VSTREAM_FLAG_NSEEK;
            break;
+       case VSTREAM_CTL_WAITPID_FN:
+           stream->waitpid_fn = va_arg(ap, VSTREAM_WAITPID_FN);
+           break;
        default:
            msg_panic("%s: bad name %d", myname, name);
        }
@@ -984,3 +1000,16 @@ VSTREAM *vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap)
     vbuf_print(&vp->buf, format, ap);
     return (vp);
 }
+
+/* vstream_peek - peek at a stream */
+
+int     vstream_peek(VSTREAM *vp)
+{
+    if (vp->buf.flags & VSTREAM_FLAG_READ) {
+       return (-vp->buf.cnt);
+    } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) {
+       return (-vp->read_buf.cnt);
+    } else {
+       return (0);
+    }
+}
index b7540bdbaa68611fb41a9149f0fe1173ef59ad8c..68c4fbe200a848d798b664ef6fe5aa3a3ecd1230 100644 (file)
@@ -27,6 +27,7 @@
   * official interface and can change without prior notice.
   */
 typedef int (*VSTREAM_FN) (int, void *, unsigned);
+typedef int (*VSTREAM_WAITPID_FN) (pid_t, WAIT_STATUS_T *, int);
 
 typedef struct VSTREAM {
     VBUF    buf;                       /* generic intelligent buffer */
@@ -39,6 +40,8 @@ typedef struct VSTREAM {
     int     write_fd;                  /* write channel (double-buffered) */
     VBUF    read_buf;                  /* read buffer (double-buffered) */
     VBUF    write_buf;                 /* write buffer (double-buffered) */
+    pid_t   pid;                       /* vstream_popen/close() */
+    VSTREAM_WAITPID_FN waitpid_fn;     /* vstream_popen/close() */
 } VSTREAM;
 
 extern VSTREAM vstream_fstd[];         /* pre-defined streams */
@@ -94,6 +97,7 @@ extern void vstream_control(VSTREAM *, int,...);
 #define VSTREAM_CTL_DOUBLE     4
 #define VSTREAM_CTL_READ_FD    5
 #define VSTREAM_CTL_WRITE_FD   6
+#define VSTREAM_CTL_WAITPID_FN 7
 
 extern VSTREAM *vstream_printf(const char *,...);
 extern VSTREAM *vstream_fprintf(VSTREAM *, const char *,...);
@@ -103,6 +107,8 @@ extern int vstream_pclose(VSTREAM *);
 
 extern VSTREAM *vstream_vfprintf(VSTREAM *, const char *, va_list);
 
+extern int vstream_peek(VSTREAM *);
+
 /* LICENSE
 /* .ad
 /* .fi
index 739af60b5579d40950eb99ed6916afd4509d0099..d6cf60f3789c697298553ce197d4cab49539d84e 100644 (file)
@@ -74,7 +74,7 @@ VSTREAM *vstream_popen(const char *command, int flags)
 {
     VSTREAM *stream;
     int     sockfd[2];
-    int     pid;
+    pid_t   pid;
     int     fd;
 
     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)