]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-20010119
authorWietse Venema <wietse@porcupine.org>
Fri, 19 Jan 2001 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 15:51:26 +0000 (15:51 +0000)
64 files changed:
postfix/FILTER_README
postfix/HISTORY
postfix/LMTP_README
postfix/LMTP_README.old [new file with mode: 0644]
postfix/Makefile.in
postfix/RELEASE_NOTES
postfix/SASL_README
postfix/conf/sample-compatibility.cf [new file with mode: 0644]
postfix/conf/sample-smtp.cf
postfix/conf/sample-smtpd.cf
postfix/conf/sample-virtual.cf [deleted file]
postfix/examples/chroot-setup/LINUX2
postfix/html/Makefile.in
postfix/html/nqmgr.8.html [deleted file]
postfix/html/smtpd.8.html
postfix/html/virtual.8.html [deleted file]
postfix/man/Makefile.in
postfix/man/man8/nqmgr.8 [deleted file]
postfix/man/man8/smtpd.8
postfix/man/man8/virtual.8 [deleted file]
postfix/src/base64/.indent.pro [deleted symlink]
postfix/src/base64/Makefile.in [deleted file]
postfix/src/base64/base64decode.c [deleted file]
postfix/src/base64/base64encode.c [deleted file]
postfix/src/bounce/bounce_notify_util.c
postfix/src/global/mail_params.h
postfix/src/global/mail_queue.c
postfix/src/global/mail_version.h
postfix/src/lmtp/Makefile.in
postfix/src/lmtp/lmtp.c
postfix/src/lmtp/lmtp.h
postfix/src/lmtp/lmtp_chat.c
postfix/src/lmtp/lmtp_proto.c
postfix/src/lmtp/lmtp_sasl.h [new file with mode: 0644]
postfix/src/lmtp/lmtp_sasl_glue.c [new file with mode: 0644]
postfix/src/lmtp/lmtp_sasl_proto.c [new file with mode: 0644]
postfix/src/lmtp/lmtp_state.c
postfix/src/lmtp/lmtp_trouble.c
postfix/src/nqmgr/.indent.pro [deleted symlink]
postfix/src/nqmgr/.printfck [deleted file]
postfix/src/nqmgr/Makefile.in [deleted file]
postfix/src/nqmgr/qmgr.c [deleted file]
postfix/src/nqmgr/qmgr.h [deleted file]
postfix/src/nqmgr/qmgr_active.c [deleted file]
postfix/src/nqmgr/qmgr_bounce.c [deleted file]
postfix/src/nqmgr/qmgr_defer.c [deleted file]
postfix/src/nqmgr/qmgr_deliver.c [deleted file]
postfix/src/nqmgr/qmgr_enable.c [deleted file]
postfix/src/nqmgr/qmgr_entry.c [deleted file]
postfix/src/nqmgr/qmgr_job.c [deleted file]
postfix/src/nqmgr/qmgr_message.c [deleted file]
postfix/src/nqmgr/qmgr_move.c [deleted file]
postfix/src/nqmgr/qmgr_peer.c [deleted file]
postfix/src/nqmgr/qmgr_queue.c [deleted file]
postfix/src/nqmgr/qmgr_rcpt_list.c [deleted file]
postfix/src/nqmgr/qmgr_scan.c [deleted file]
postfix/src/nqmgr/qmgr_transport.c [deleted file]
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpstone/smtp-sink.c
postfix/src/smtpstone/smtp-source.c
postfix/src/util/make_dirs.c
postfix/src/virtual/virtual [new file with mode: 0755]

index 5c8c495c0e235db65b8caa665d4fc2725f607361..243c2f4c95bf5dde4321623d66487773a7801f35 100644 (file)
@@ -60,23 +60,20 @@ The filter program can start out as a simple shell script like this:
     # Exit codes from <sysexits.h>
     EX_TEMPFAIL=75
     EX_UNAVAILABLE=69
-    STATUS=$EX_TEMPFAIL
 
     # Clean up when done or when aborting.
-    trap "rm -f in.$$; exit $STATUS" 0 1 2 3 15
-
-    quit() { STATUS=${1-$?}; exit; }
+    trap "rm -f in.$$" 0 1 2 3 15
 
     # Start processing.
-    cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; quit $EX_TEMPFAIL; }
+    cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }
 
-    cat >in.$$ || { echo Cannot save mail to file; quit $EX_TEMPFAIL; }
+    cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }
 
-    # filter <in.$$ || { echo Message content rejected; quit $EX_UNAVAILABLE; }
+    # filter <in.$$ || { echo Message content rejected; exit $EX_UNAVAILABLE; }
 
     $SENDMAIL "$@" <in.$$
 
-    STATUS=$?
+    exit $?
 
 The idea is to first capture the message to file and then run the
 content through run a third-party content filter program.  If the
index 119b6424504bd17673535eff449d9aa6558b4a6b..e735244566710f3bd23eeaa10b205e56e8aedf9e 100644 (file)
@@ -4672,13 +4672,6 @@ Apologies for any names omitted.
        core instead if issuing an error message. This is what I
        get for accepting code that I cannot test myself.
 
-20001220
-
-       Feature: merged in Andrew McNamara's virtual delivery agent
-       (a table-driven agent that does not require recipients to
-       have UNIX accounts, and that implements a safe subset of
-       the default local delivery agent). Files: virtual/*.
-
 20001221
 
        Code cleanup: configuration parameters that are $name
@@ -4708,3 +4701,36 @@ Apologies for any names omitted.
        Bugfix: soft errors in client hostname lookups would be
        treated as hard errors. Fix by Michael Herrmann
        (informatik.tu-muenchen.de). File: smtpd/smtpd_peer.c.
+
+20010110
+
+       Bugfix: the mkdir() EEXIST race condition workaround was
+       not complete.  Matthias Andree, Daniel Roesen.  Files:
+       global/mail_queue.c, util/make_dirs.c.
+
+20010111
+
+       Portability: IRIX 6.5.10 defines sa_len as a macro, causing
+       a name collision with a variable used by Postfix. Roberto
+       Totaro, enigma.ethz.ch. File:  smtpstone/smtp-source.c.
+
+20010116
+
+       Bugfix: REJECT by header/body_checks was flagged in smtpd
+       as a bounce, should be policy, in order to make postmaster
+       notifications more consistent. File: smtpd/smtpd.c.
+
+       Merged updated chroot setup procedure by Matthias Andree.
+       Files: examples/chroot-setup/LINUX2.
+
+20010117
+
+       Formatting: changed the seconds and days formats in the
+       "your mail is delayed" text so that it does not switch to
+       scientific notation. File: bounce/bounce_notify_util.c.
+
+20010119
+
+       Feature: SASL support for the LMTP client. Recent CYRUS
+       software requires this for Postfix over TCP sockets.
+       This was just a cloning operation.
index 873c6c3d10878566f0ac8e3dd45e7be1c17af25d..1c44a13959479f188d095f237795c57c7e89b29e 100644 (file)
-BEGIN WARNING
-=============
+[Based on information that was provided by Amous Gouaux]
 
-The information in this file is outdated. The Postfix LMTP server
-can now make connections over UNIX-domain sockets. 
+Postfix LMTP support
+====================
+
+LMTP stands for Local Mail Transfer Protocol, and is detailed in
+RFC2033.  This protocol is used to communicate with the final
+delivery agent, which may be on the local host or a remote host.
+
+This protocol opens up interesting possibilities: one Postfix front
+end system can drive multiple mailbox back end systems over LMTP.
+As the mail load increases you add Postfix front end systems and
+LMTP mailbox back end systems.  You can use LDAP or mysql to share
+the user database among the front end and back end systems.
+
+Postfix LMTP support is based on a modified version of the Postfix
+SMTP client. The initial version was by Philip A.  Prindeville of
+Mirapoint, Inc., USA. This code was modified further by Amos Gouaux
+of University of Texas at Dallas, Richardson, USA.  Wietse Venema
+reduced the code to its present shape.
+
+
+Overview
+========
+
+Most of the examples in this document involve the CMU Cyrus IMAP/POP
+server, available from:
+
+    http://asg.web.cmu.edu/cyrus/
 
-With connections over TCP sockets, some Cyrus implementations insist
-on SASL-style authentication, which is not supported by the Postfix
-LMTP client. In that case, use UNIX-domain sockets instead.
+While certainly not the only application that could make use of LMTP,
+it tends to be the most discussed.  These examples are based on the
+forthcoming Cyrus 2.0.10, at least at the time of writing.  The 2.x
+branch of Cyrus places greater emphasis on LMTP delivery than the
+previous releases.  Those using older releases of Cyrus can find a
+discussion in the appendix of this document.
+
+There are a variety of ways LMTP delivery can be configured in
+Postfix.  The two basic flavors are delivery over UNIX-domain sockets
+and delivery over TCP sockets.  Both flavors can be specified in
+either the Postfix main.cf or in a transport map.  The best approach
+to use depends upon the arrangement of your servers and the desired
+level of parallelization.  Please be sure to study this entire
+document as there are trade-offs in convenience and performance with
+these different approaches.
 
 The precise syntax for UNIX-domain and TCP connection endpoints is
 given in the lmtp(8) manual page.
 
+
+Using main.cf configuration
+===========================
+
+This is the simplest LMTP configuration.  The settings
+local_transport, mailbox_transport, and fallback_transport can
+support the following connections:
+
+1.  LMTP over TCP sockets.
+
+    mailbox_transport = lmtp
+
+    Instead of delivering local mail to a mail box such as
+    /var/mail/$user, a connection will be made over TCP to an LMTP
+    server.  Currently the default port for this connection is 24,
+    but this can be customized in the "/etc/services" file.
+
+    NOTE:
+
+        With connections over TCP sockets, some Cyrus implementations
+        insist on SASL-style authentication, which is not currently
+        supported by the Postfix LMTP client.  See the examples below 
+        for additional details.
+
+
+2.  LMTP over UNIX-domain sockets.
+
+    mailbox_transport = lmtp:unix:/path/name
+
+    In this case the LMTP connection will be made over a UNIX-domain
+    socket.  This "/path/name" should be the socket created by the
+    LMTP server on the local machine.
+
+    NOTE 1:
+
+        If you configured Cyrus using the "--with-libwrap" option, be 
+        sure to allow access to the "lmtpd" service from "0.0.0.0".
+        Otherwise LMTP deliveries over UNIX-domain sockets will be
+        blocked.  See the examples below for more on using libwrap.
+
+    NOTE 2:
+
+       If you run the lmtp client chrooted, the interpretation of
+       the /path/name is relative to the Postfix queue directory
+       (typically, /var/spool/postfix).
+
+    NOTE 3:
+
+       By default, the Postfix LMTP client does not run chrooted.
+       With LMTP delivery to the local machine there is no good
+       reason to run the Postfix LMTP client chrooted.
+
+
 Examples:
 
+1.  LMTP over UNIX-domain sockets.
+
+    To utilize UNIX-domain sockets for the communication between
+    Postfix and Cyrus, the corresponding configuration files should
+    look something like this:
+
+    /etc/cyrus.conf:
+
+        SERVICES { 
+            ... 
+            lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1
+            ... 
+        } 
+
+    /etc/postfix/main.cf:
+
+        mailbox_transport = lmtp:unix:/var/imap/socket/lmtp
+
+    In this case, mail that is resolved to be local will be delivered
+    to the Cyrus lmtpd server via the socket "/var/imap/socket/lmtp".  
+
+    If you configured Cyrus using the "--with-libwrap" option, you
+    will need the following:
+
+    /etc/hosts.allow:
+
+        lmtpd : 0.0.0.0
+
+2.  LMTP over TCP sockets.
+
+    For this example, suppose the following files are configured
+    thusly: 
+
+    /etc/cyrus.conf:
+
+        SERVICES { 
+            ... 
+            lmtp cmd="lmtpd -a" listen="127.0.0.1:lmtp" prefork=0 
+            ... 
+        } 
+
+XXX does this mean that connections will be accepted only on 127.0.0.1?
+
+    /etc/services:
+
+        lmtp 2003/tcp
+
+    /etc/postfix/main.cf:
+
+        mailbox_transport = lmtp
+
+    /etc/postfix/master.cf:
+
+        lmtp      unix  -       -       n       -       -       lmtp
+
+    Mail that Postfix resolves to be local will be delivered via TCP
+    to the Cyrus LMTP server.  Postfix will make a connection to port
+    2003 on the local host, subsequently transmitting the message to
+    the lmtpd server managed by the Cyrus master process.  Since
+    Postfix does not currently support LMTP-AUTH, the "-a" lmtpd
+    option is required.
+
+    CAUTION:
+
+        If you run lmtpd with the "-a" option, be certain that you
+        restrict what systems can connect to this service.  This can
+        be done in either one of two ways:
+
+        a.  Compile Cyrus with libwrap support, configuring
+            "/etc/hosts.allow" to restrict access to this service to
+            only your mail server.
+
+        b.  In the cyrus.conf file, for the "listen" argument to the
+            "lmtp" service, specify the address (in this case
+            localhost), that the service should bind to.  This can
+            also be convenient if you have a private network between
+            your Postfix server and your Cyrus server.
+
+        If neither of these actions are taken, anybody will be able
+        to drop junk into your Cyrus message store!  
+
+
+3.  LMTP over TCP sockets, using hosts.allow.
+
+    While similar to the previous example, this one varies in how the
+    lmtpd service is protected from unauthorized use.  Instead of
+    binding the lmtpd service to a specific Internet address, access
+    will be controlled using the "/etc/hosts.allow" tcp_wrappers
+    configuration file.  The tcp_wrappers package is available from:
+
+        ftp://ftp.porcupine.org/pub/security/index.html
+
+    To take advantage of tcp_wrappers, Cyrus will need to be
+    configured using the "--with-libwrap" option.  See the Cyrus
+    documentation for more details.
+
+    Here are excerpts of the pertinent files:
+
+    /etc/hosts.allow:
+
+        lmtpd : localhost : ALLOW
+        lmtpd : ALL@ALL : DENY
+
+    /etc/cyrus.conf:
+
+        SERVICES { 
+            ... 
+            lmtp cmd="lmtpd -a" listen="lmtp" prefork=0 
+            ... 
+        } 
+
+    /etc/services:
+
+        lmtp 2003/tcp
+
+    /etc/postfix/main.cf:
+
+        mailbox_transport = lmtp
+
+    The syntax shown in the hosts.allow excerpt above is valid if
+    tcp_wrappers is compiled using a "make" argument of:
+
+        STYLE=-DPROCESS_OPTIONS
+
+    See the tcp_wrappers hosts_options(5) man page for more details.
+
+
+Using transport map configuration
+=================================
+
+This approach is quite similar to specifying the LMTP service in the
+Postfix main.cf configuration file.  However, now we will use a
+transport map to route mail to the appropriate LMTP server.  Why
+might this approach be useful?  This could be handy if you wish to
+route mail for multiple domains to their respective mail retrieval
+(IMAP/POP) server.  Example:
+
     /etc/postfix/transport:
+
        domain1.name            lmtp1:unix:/path/name
        domain2.name            lmtp2:lmtp2host
 
     /etc/postfix/master.cf:
+
         lmtp1      unix  -       -       n       -       -       lmtp
         lmtp2      unix  -       -       n       -       -       lmtp
 
-The first example (domain1) uses UNIX-domain connections, the second
-example (domain2) uses TCP. 
+    /etc/postfix/main.cf:
 
-For optimal use of connection caching, specify separate mail delivery
-transports for each domain that receives mail via LMTP:
+        transport_maps = hash:/etc/postfix/transport
 
-END WARNING
-===========
+Instead of "hash", use the map type of your choice.  Some systems use
+"dbm" instead.  Use "postconf -m" to find out what map types are
+supported.
 
-Postfix LMTP support
-====================
 
-Postfix LMTP support is based on a modified version of the Postfix
-SMTP client. The initial version was by Philip A.  Prindeville of
-Mirapoint, Inc., USA. This code was modified further by Amos Gouaux
-of University of Texas at Dallas, Richardson, USA.  Wietse Venema
-reduced the code to its present shape.
+Performance considerations
+==========================
 
-Postfix can be configured to talk to a local or remote LMTP server.
-Most people will run the LMTP server on the same machine that runs
-Postfix. However, a remote LMTP server can be useful if Postfix
-runs on mail relay server(s) that feed incoming mail directly to
-the appropriate mailbox server(s). This way, mailbox servers do
-not need to run an SMTP server at all.  Tidy all the way around.
+Hopefully the preceding discussion has seemed pretty straight
+forward.  Now things get interesting.  After reading the following
+you will see that there are more factors to consider when setting up
+LMTP services.
 
-Configuring the mailbox server (local or remote)
-================================================
 
-On the mailbox server, in this case a CMU Cyrus imapd/popd server,
-add the following to /etc/services:
+Single instance message store
+=============================
 
-    pop3            110/tcp                         # Cyrus POP3
-    imap            143/tcp                         # Cyrus IMAP4
-    lmtp            24/tcp
+Presently this topic is more pertinent to sites running Cyrus, but
+may be a factor with other applications as well.
 
-Next, put the following in /etc/inetd.conf:
+Since 1.6.22, Cyrus has had the feature that if a message containing
+multiple recipients is received via the LMTP protocol, and all these
+recipients were on the same Cyrus partition, only one instance of
+this message would be written to the file system.  The other
+recipients would then see a hard link of this single instance.
+Depending on your user base, this can be considerable motivation to
+using LMTP. 
 
-    lmtp    stream  tcp     nowait  cyrus   /usr/sbin/tcpd  /usr/local/cyrus/bin/deliver -e -l
+However, there is a catch: currently the Postfix local delivery
+mechanisms are only designed to handle one recipient at a time, which
+in most cases is more than adequate.  So, if you wish to support
+single instance message store delivery, you will have to use a
+transport table to map these users to the appropriate LMTP
+destination.
 
-/usr/sbin/tcpd is from the tcp_wrappers package.  You want this to
-make sure only your mail relay(s) can talk to the LMTP server.
-Postfix by default does multiple deliveries per LMTP session
-(connection caching), so do not worry about the overhead of
-tcp_wrapping the LMTP port.
+While the simplest thing to do would be to list the entire domain in
+the transport map for LMTP delivery, this by-passes alias expansion
+for otherwise local addresses.  If the site is to run software via
+aliases, like most Mailing List Management (MLM) software, a more
+complex solution is required.  Fortunately, a virtual table should do
+the trick.
 
-On some systems, tcpd is built into inetd, so you do not have to
-specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd
-can do a similar job of logging and access control.
+As an example, suppose we wanted to support single instance message
+store delivery for the domain "example.org".  The configuration files
+for this domain could look something like this:
+
+    /etc/postfix/virtual:
+
+        mlist@example.org   mlist@localhost
+
+    /etc/postfix/transport:
+
+        example.org         lmtp:unix:/var/imap/socket/lmtp
 
-Configuring Postfix
-===================
+    /etc/postfix/aliases:
 
-Similar changes to /etc/services:
+        mlist:              "|/path/to/mlm/software"
 
-    lmtp            24/tcp
+    /etc/postfix/master.cf:
 
-You may have to add the following entry to /etc/postfix/master.cf:
+        lmtp      unix  -       -       n       -       -       lmtp
 
-    lmtp      unix  -       -       n       -       -       lmtp
+    /etc/postfix/main.cf:
 
-NOTE:  Root privileges are not necessary!
+        mydestination = localhost, $myhostname, $mydomain
+        virtual_maps = hash:/etc/postfix/virtual        
+        transport_maps = hash:/etc/postfix/transport
+        alias_maps = hash:/etc/postfix/aliases
+        alias_database = hash:/etc/postfix/aliases
 
-Put this in /etc/postfix/transport:
+    /etc/cyrus.conf:
 
-    inbox.domain.org     lmtp:inbox.domain.org
+        SERVICES { 
+            ... 
+            lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1
+            ... 
+        } 
 
-Naturally, this means we also need in /etc/postfix/main.cf:
+Breaking things down, we begin with the address "mlist@example.org",
+which represents a mailing list.  By placing an entry in the virtual
+map to direct this mail to "mlist@localhost", we can override the
+transport map that would by default route all "@example.org" mail to
+a LMTP server via a UNIX-domain socket.
 
-    transport_maps      = hash:/etc/postfix/transport
+To summarize, all mail that is to be processed by an alias entry must 
+first be diverted with a virtual table entry so that it does not fall 
+into the more general routing established by the transport table.
 
-Instead of "hash", use the map type of your choice. Some systems
-use "dbm" instead. Use "postconf -m" to find out what map types
-are supported.
 
 Improving connection caching performance
 ========================================
@@ -112,6 +359,7 @@ You can prevent the LMTP client from switching between servers by
 configuring a separate mail delivery transport for each LMTP server:
 
     /etc/postfix/master.cf:
+
         lmtp1      unix  -       -       n       -       -       lmtp
         lmtp2      unix  -       -       n       -       -       lmtp
           .         .    .       .       .       .       .        .
@@ -121,5 +369,99 @@ transport is used for all deliveries to the LMTP server #1, the
 mail lmtp2 transport for the LMTP server #2, and so on.
 
     /etc/postfix/transport:
+
         foo.com lmtp1:lmtp1host
         bar.com lmtp2:lmtp2host
+
+
+Appendix: Older Cyrus versions
+==============================
+
+First of all, if you are using a Cyrus 2.x version prior to 2.0.10,
+it would be good to upgrade.  The previous 2.x releases were beta
+releases, and numerous bug fixes and enhancements have been
+incorporated into the 2.0.10 release.
+
+Further back, 1.6.24 was the last pre-2.x production release.
+(Actually, there was a 1.6.25-BETA, but it is uncertain whether this
+will be released officially as CMU is now focusing support on the 2.x
+branch.)  The following discussion touches on how to configure the
+Postfix LMTP facilities with Cyrus 1.6.24.
+
+One of the significant differences between Cyrus 1.x and 2.x is the
+inclusion of the "master" process in 2.x.  This "master" process is
+responsible for running the various components of Cyrus, such as
+imapd, pop3d, and lmtpd.  Prior to 2.x, these services were managed
+by inetd, the Internet services daemon.
+
+To utilize LMTP delivery with Cyrus 1.6.24, the first thing to do is
+configure inetd.  This involves the following file edits:
+
+    /etc/services:
+
+        lmtp 2003/tcp
+
+    /etc/inetd.conf:
+
+        lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/cyrus/bin/deliver -e -l
+
+    /etc/hosts.allow:
+
+        deliver : localhost : ALLOW
+        deliver : ALL@ALL : DENY
+
+The "/usr/sbin/tcpd" is from the tcp_wrappers package, which is
+discussed in the example "LMTP over TCP sockets, using hosts.allow."
+It is important that you wrap this LMTP port to protect it from
+unauthorized access.
+
+On some systems, tcpd is built into inetd, so you do not have to
+specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd
+can do a similar job of logging and access control.
+
+Now comes the Postfix configuration.  Basically, the Cyrus 2.x
+discussions regarding LMTP delivery over TCP are also applicable to
+Cyrus 1.x, with the exception of the "/etc/cyrus.conf" file.  A
+typical Postfix configuration might look like this:
+
+    /etc/postfix/master.cf:
+
+        lmtp      unix  -       -       n       -       -       lmtp
+
+    /etc/postfix/main.cf:
+
+        mailbox_transport = lmtp
+
+It is also possible to use the transport map to route mail to your
+Cyrus 1.6.24 LMTP server:
+
+    /etc/postfix/transport:
+
+       domain1.name            lmtp1:lmtp1host
+       domain2.name            lmtp2:lmtp2host
+
+    /etc/postfix/master.cf:
+
+        lmtp1      unix  -       -       n       -       -       lmtp
+        lmtp2      unix  -       -       n       -       -       lmtp
+
+    /etc/postfix/main.cf:
+
+        transport_maps = hash:/etc/postfix/transport
+
+If you have read the discussion covering the Cyrus 2.x installation,
+you will notice the one significant difference with the Postfix
+configuration is the lack of mention of the UNIX-domain sockets.
+That is because delivery over UNIX-domain sockets is new with Cyrus
+2.x, yet another reason to upgrade.  :-)
+
+
+
+# Local Variables:
+# mode: text
+# mode: flyspell
+# fill-column: 69
+# End:
+
+
+
diff --git a/postfix/LMTP_README.old b/postfix/LMTP_README.old
new file mode 100644 (file)
index 0000000..873c6c3
--- /dev/null
@@ -0,0 +1,125 @@
+BEGIN WARNING
+=============
+
+The information in this file is outdated. The Postfix LMTP server
+can now make connections over UNIX-domain sockets. 
+
+With connections over TCP sockets, some Cyrus implementations insist
+on SASL-style authentication, which is not supported by the Postfix
+LMTP client. In that case, use UNIX-domain sockets instead.
+
+The precise syntax for UNIX-domain and TCP connection endpoints is
+given in the lmtp(8) manual page.
+
+Examples:
+
+    /etc/postfix/transport:
+       domain1.name            lmtp1:unix:/path/name
+       domain2.name            lmtp2:lmtp2host
+
+    /etc/postfix/master.cf:
+        lmtp1      unix  -       -       n       -       -       lmtp
+        lmtp2      unix  -       -       n       -       -       lmtp
+
+The first example (domain1) uses UNIX-domain connections, the second
+example (domain2) uses TCP. 
+
+For optimal use of connection caching, specify separate mail delivery
+transports for each domain that receives mail via LMTP:
+
+END WARNING
+===========
+
+Postfix LMTP support
+====================
+
+Postfix LMTP support is based on a modified version of the Postfix
+SMTP client. The initial version was by Philip A.  Prindeville of
+Mirapoint, Inc., USA. This code was modified further by Amos Gouaux
+of University of Texas at Dallas, Richardson, USA.  Wietse Venema
+reduced the code to its present shape.
+
+Postfix can be configured to talk to a local or remote LMTP server.
+Most people will run the LMTP server on the same machine that runs
+Postfix. However, a remote LMTP server can be useful if Postfix
+runs on mail relay server(s) that feed incoming mail directly to
+the appropriate mailbox server(s). This way, mailbox servers do
+not need to run an SMTP server at all.  Tidy all the way around.
+
+Configuring the mailbox server (local or remote)
+================================================
+
+On the mailbox server, in this case a CMU Cyrus imapd/popd server,
+add the following to /etc/services:
+
+    pop3            110/tcp                         # Cyrus POP3
+    imap            143/tcp                         # Cyrus IMAP4
+    lmtp            24/tcp
+
+Next, put the following in /etc/inetd.conf:
+
+    lmtp    stream  tcp     nowait  cyrus   /usr/sbin/tcpd  /usr/local/cyrus/bin/deliver -e -l
+
+/usr/sbin/tcpd is from the tcp_wrappers package.  You want this to
+make sure only your mail relay(s) can talk to the LMTP server.
+Postfix by default does multiple deliveries per LMTP session
+(connection caching), so do not worry about the overhead of
+tcp_wrapping the LMTP port.
+
+On some systems, tcpd is built into inetd, so you do not have to
+specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd
+can do a similar job of logging and access control.
+
+Configuring Postfix
+===================
+
+Similar changes to /etc/services:
+
+    lmtp            24/tcp
+
+You may have to add the following entry to /etc/postfix/master.cf:
+
+    lmtp      unix  -       -       n       -       -       lmtp
+
+NOTE:  Root privileges are not necessary!
+
+Put this in /etc/postfix/transport:
+
+    inbox.domain.org     lmtp:inbox.domain.org
+
+Naturally, this means we also need in /etc/postfix/main.cf:
+
+    transport_maps      = hash:/etc/postfix/transport
+
+Instead of "hash", use the map type of your choice. Some systems
+use "dbm" instead. Use "postconf -m" to find out what map types
+are supported.
+
+Improving connection caching performance
+========================================
+
+After delivering a message via LMTP, Postfix will keep the connection
+open for a while, so that it can be reused for a subsequent delivery.
+This reduces overhead of LMTP servers that create one process per
+connection.  
+
+For LMTP connection caching to work, the Postfix LMTP client should
+not switch destination hosts.  This is no problem when you run only
+one LMTP server. However, if you run multiple LMTP servers, this
+can be an issue.
+
+You can prevent the LMTP client from switching between servers by
+configuring a separate mail delivery transport for each LMTP server:
+
+    /etc/postfix/master.cf:
+        lmtp1      unix  -       -       n       -       -       lmtp
+        lmtp2      unix  -       -       n       -       -       lmtp
+          .         .    .       .       .       .       .        .
+
+Configure transport table entries such that the lmtp1 mail delivery
+transport is used for all deliveries to the LMTP server #1, the
+mail lmtp2 transport for the LMTP server #2, and so on.
+
+    /etc/postfix/transport:
+        foo.com lmtp1:lmtp1host
+        bar.com lmtp2:lmtp2host
index edbf1a070e1dc0ed2a31254db540eb3d2fdc3148..ec32d0b78b82daa7e1f3304ebc1fe956c8dd80fe 100644 (file)
@@ -6,7 +6,7 @@ DIRS    = src/util src/global src/dns src/master src/postfix src/smtpstone \
        src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
        src/showq src/postalias src/postcat src/postconf src/postdrop \
        src/postkick src/postlock src/postlog src/postmap src/postsuper \
-       src/nqmgr src/spawn src/flush src/virtual # src/base64 proto man html
+       src/spawn src/flush # proto man html
 
 default: update
 
index 3e92932c6044c34679ff2fc3214e85aafa18a6e2..af3e6c7bfc4a93b798d039958e3952f0d322bef9 100644 (file)
@@ -1,3 +1,6 @@
+REJECT by header/body_checks are now flagged as policy violations
+rather than bounces, for consistency in postmaster notifications.
+
 Major changes with snapshot-20001217
 ====================================
 
index 60da041b0e6fa1b5600d9f488a8e511a21545b7d..d793787e8946e57d0c4c8cf0c17c6ea966a15fce 100644 (file)
@@ -1,10 +1,23 @@
 WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 ===============================================================
 
-Do not use this code.  The Postfix SASL support is based on the
-Cyrus SASL library, which has not enough documentation about how
-the software is supposed to work. It is not clear if the code is
-safe enough for security-critical applications.
+This code is not blessed by Wietse.
+
+People who go to the trouble of installing Postfix may have the
+expectation that Postfix is more secure than some other mailers.
+
+With SASL authentication enabled in the Postfix SMTP client and
+SMTP server, Postfix becomes no more secure than other mail systems
+that use the Cyrus SASL library.
+
+The Cyrus SASL library has too little documentation about how the
+software is supposed to work; and it is too much code to be used
+in a security-sensitive program such as an SMTP client or server.
+
+However, you are pretty much required to build with SASL support
+if you are going to use the LMTP interface of the Cyrus delivery
+agent.  This interface is much faster than forking a new process
+for every message delivery.
 
 Postfix+SASL 1.5.5 appears to work on RedHat 6.1 (pwcheck_method
 set to shadow or sasldb), Solaris 2.7 (pwcheck_method set to shadow
@@ -14,9 +27,6 @@ Note that this seems to be related to the auto_transition switch in
 SASL. Note also that the Cyrus SASL documentation says that it is
 pointless to enable that if you use "sasldb" for "pwcheck_method".
 
-SASL is a lot of complex code. In a future version the Postfix SASL
-code is likely to be put outside the SMTP server.
-
 Introduction
 ============
 
@@ -52,6 +62,12 @@ Reportedly, Microsoft Internet Explorer version 5 requires the
 non-standard SASL LOGIN authentication method. To enable this
 authentication method, specify ``./configure --enable-login''.
 
+Reportedly, older Microsoft software mis-implements the AUTH
+protocol, and requires that the server replies to EHLO with
+"250-AUTH=stuff..." instead of "250-AUTH stuff...". To accomodate
+such clients, set "allow_broken_auth_clients = yes" in the main.cf
+file.
+
 Building Postfix with SASL authentication support
 =================================================
 
diff --git a/postfix/conf/sample-compatibility.cf b/postfix/conf/sample-compatibility.cf
new file mode 100644 (file)
index 0000000..329ee4c
--- /dev/null
@@ -0,0 +1,66 @@
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
+# This file contains example settings of Postfix configuration
+# parameters that control compatibility with broken software.
+
+# 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_always_send_ehlo parameter specifies that the SMTP client
+# should always send EHLO at the start of an SMTP session.
+# 
+# By default, Postfix sends EHLO only when the word "ESMTP" appears
+# in the server greeting banner (example: 220 spike.porcupine.org
+# ESMTP Postfix).
+#
+smtp_always_send_ehlo = no
+
+# The smtp_never_send_ehlo parameter specifies that the SMTP client 
+# should never send EHLO at the start of an SMTP session.
+#
+# By default, Postfix sends EHLO whenever the word "ESMTP" appears
+# in the server greeting banner (example: 220 spike.porcupine.org
+# ESMTP Postfix).
+#
+smtp_never_send_ehlo = no
+
+# The smtp_skip_4xx_greeting parameter controls what happens when
+# an SMTP server greets us with a 4XX status code (go away, try
+# again later). 
+#
+# By default, Postfix moves on the the next mail exchanger. Specify
+# "smtp_skip_4xx_greeting = no" if Postfix should defer delivery
+# immediately.
+# 
+smtp_skip_4xx_greeting = yes
+
+# The smtp_skip_5xx_greeting parameter controls what happens when
+# an SMTP server greets us with a 5XX status code (go away, do not
+# try again later).
+#
+# By default, Postfix moves on the the next mail exchanger. Specify
+# "smtp_skip_5xx_greeting = no" if Postfix should bounce the mail
+# immediately.
+# 
+smtp_skip_5xx_greeting = yes
+
+# 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
+
+# The strict_rfc821_envelopes configuration parameter controls whether
+# the Postfix SMTP server requires that MAIL FROM and RCPT TO addresses
+# are specified within <>, and that MAIL FROM and RCPT TO addresses 
+# do not contain RFC822-style comments or phrases.  It's great to
+# stop SPAM mailers. But it also trips up broken peecee clients.
+#
+# By default, Postfix SMTPD allows RFC822 syntax in MAIL FROM and RCPT TO.
+#
+strict_rfc821_envelopes = no
index 0750e0f213fa36ecf8c2800d41527d6240725980..ccaf5ec64d55462a91ab37551bc1ada207146264 100644 (file)
@@ -66,11 +66,24 @@ smtp_never_send_ehlo = no
 #smtp_bind_address=111.222.333.444
 
 # 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
+# an SMTP server greets us with a 4XX status code (go away, try
+# again later).
+#
+# By default, Postfix moves on the the next mail exchanger. Specify
+# "smtp_skip_4xx_greeting = no" if Postfix should defer delivery
+# immediately.
+#
+smtp_skip_4xx_greeting = yes
+
+# The smtp_skip_5xx_greeting parameter controls what happens when
+# an SMTP server greets us with a 5XX status code (go away, do not
+# try again later).
+#
+# By default, Postfix moves on the the next mail exchanger. Specify
+# "smtp_skip_5xx_greeting = no" if Postfix should bounce the mail 
+# immediately.
+#
+smtp_skip_5xx_greeting = yes
 
 # The smtp_skip_quit_response parameter controls whether the SMTP
 # client waits for the response to the QUIT command. The default is
index 02df492467e55a103d817ab2badf2750e792e196..56f30180023cbaa411fc24c8f5b5566f42e7c51f 100644 (file)
@@ -63,6 +63,16 @@ smtpd_recipient_limit = 1000
 #
 smtpd_timeout = 300s
 
+# The strict_rfc821_envelopes configuration parameter controls whether
+# the Postfix SMTP server requires that MAIL FROM and RCPT TO addresses
+# are specified within <>, and that MAIL FROM and RCPT TO addresses
+# do not contain RFC822-style comments or phrases.  It's great to
+# stop SPAM mailers. But it also trips up broken peecee clients.
+# 
+# By default, Postfix SMTPD allows RFC822 syntax in MAIL FROM and RCPT TO.
+# 
+strict_rfc821_envelopes = no
+
 #
 # TARPIT CONTROLS
 #
diff --git a/postfix/conf/sample-virtual.cf b/postfix/conf/sample-virtual.cf
deleted file mode 100644 (file)
index d660d6b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
-# HERE JUST SERVES AS AN EXAMPLE.
-#
-# This file contains example settings of Postfix configuration
-# parameters that control virtual database lookups.
-
-# The virtual_maps parameter specifies optional lookup tables to
-# redirect specific addresses or even complete domains to another
-# address. This is typically used to implement virtual domain support.
-# 
-# By default, no address redirection is done. 
-#
-# If you use this feature, run "postmap /etc/postfix/virtual" to 
-# build the necessary DBM or DB file after change.
-#
-# It may take a minute or so before the change becomes visible.
-# Use "postfix reload" to eliminate the delay.
-#
-# virtual_maps = dbm:/etc/postfix/virtual
-# virtual_maps = hash:/etc/postfix/virtual
-# virtual_maps = hash:/etc/postfix/virtual, nis:virtual
-# virtual_maps = hash:/etc/postfix/virtual, netinfo:/virtual
-virtual_maps = 
index 78aaab251ac0658d3927d12a92b5c319f84a9dce..dc9419db11349b56cc0538ba53e5ba57f4db207a 100644 (file)
@@ -1,9 +1,14 @@
 #! /bin/sh
 
 # LINUX2 - shell script to set up a Postfix chroot jail for Linux
-# Tested on SuSE Linux 5.3 (libc5) and 6.4 (glibc2.1)
+# Tested on SuSE Linux 5.3 (libc5) and 7.0 (glibc2.1)
 
-# Copyright (c) 2000 by Matthias Andree
+# Other testers reported as working:
+#
+# 2001-01-15 Debian sid (unstable)
+#            Christian Kurz <shorty@getuid.de>
+
+# Copyright (c) 2000 - 2001 by Matthias Andree
 # Redistributable unter the MIT-style license that follows:
 # Abstract: "do whatever you want except hold somebody liable or change
 # the copyright information".
 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 # IN THE SOFTWARE.
 
+# 2000-09-29
+# v0.1: initial release
+
+# 2000-12-05
+# v0.2: copy libdb.* for libnss_db.so
+#       remove /etc/localtime in case it's a broken symlink
+#       restrict find to maxdepth 1 (faster)
+
+# $Log: LINUX2,v $
+# Revision 1.4  2001/01/15 09:36:35  emma
+# add note it was successfully tested on Debian sid
+#
+
+CP="cp -p"
+
 cond_copy() {
   # find files as per pattern in $1
   # if any, copy to directory $2
   dir=`dirname "$1"`
   pat=`basename "$1"`
-  lr=`find "$dir" -name "$pat"`
+  lr=`find "$dir" -maxdepth 1 -name "$pat"`
   if test ! -d "$2" ; then exit 1 ; fi
-  if test "x$lr" != "x" ; then cp -p $1 "$2" ; fi
+  if test "x$lr" != "x" ; then $CP $1 "$2" ; fi
 } 
 
 set -e
@@ -47,10 +67,18 @@ mkdir -p etc lib usr/lib/zoneinfo
 # find localtime (SuSE 5.3 does not have /etc/localtime)
 lt=/etc/localtime
 if test ! -f $lt ; then lt=/usr/lib/zoneinfo/localtime ; fi
+if test ! -f $lt ; then lt=/usr/share/zoneinfo/localtime ; fi
 if test ! -f $lt ; then echo "cannot find localtime" ; exit 1 ; fi
-cp -p -f $lt /etc/services /etc/resolv.conf /etc/nsswitch.conf etc
-cp -p -f /etc/host.conf /etc/hosts /etc/passwd etc
+rm -f etc/localtime
+
+# copy localtime and some other system files into the chroot's etc
+$CP -f $lt /etc/services /etc/resolv.conf /etc/nsswitch.conf etc
+$CP -f /etc/host.conf /etc/hosts /etc/passwd etc
 ln -s -f /etc/localtime usr/lib/zoneinfo
 
-cond_copy '/lib/libnss_*' lib
-cond_copy '/lib/libresolv*' lib
\ No newline at end of file
+# copy required libraries into the chroot
+cond_copy '/lib/libnss_*.so*' lib
+cond_copy '/lib/libresolv.so*' lib
+cond_copy '/lib/libdb.so*' lib
+
+postfix reload
index c15b21a1f2a97e681f25eb4d13dbf75c81cf8f91..9374acc1abe421595e29e13290e11b40856361ae 100644 (file)
@@ -5,7 +5,7 @@ SHELL   = /bin/sh
 DAEMONS        =  bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
        lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
        showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
-       nqmgr.8.html spawn.8.html flush.8.html virtual.8.html
+       spawn.8.html flush.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 \
@@ -51,12 +51,6 @@ local.8.html: ../src/local/local.c
 master.8.html: ../src/master/master.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
-nqmgr.8.html: ../src/nqmgr/qmgr.c
-       srctoman $? | sed -e 's/qmgr[^_]/n&/' \
-                         -e 's/qmgr$$/n&/' \
-                         -e 's/QMGR[^_]/N&/' | \
-           nroff -man | man2html | postlink >$@
-
 pickup.8.html: ../src/pickup/pickup.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
@@ -81,9 +75,6 @@ smtpd.8.html: ../src/smtpd/smtpd.c
 trivial-rewrite.8.html: ../src/trivial-rewrite/trivial-rewrite.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
-virtual.8.html: ../src/virtual/virtual.c
-       srctoman $? | nroff -man | man2html | postlink >$@
-
 postalias.1.html: ../src/postalias/postalias.c
        srctoman $? | nroff -man | man2html | postlink >$@
 
diff --git a/postfix/html/nqmgr.8.html b/postfix/html/nqmgr.8.html
deleted file mode 100644 (file)
index 624352a..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-<html> <head> </head> <body> <pre>
-
-
-
-NQMGR(8)                                                 NQMGR(8)
-
-
-<b>NAME</b>
-       nqmgr - Postfix queue manager
-
-<b>SYNOPSIS</b>
-       <b>nqmgr</b> [generic Postfix daemon options]
-
-<b>DESCRIPTION</b>
-       The  <b>nqmgr</b>  daemon awaits the arrival of incoming mail and
-       arranges for its delivery via Postfix delivery  processes.
-       The actual mail routing strategy is delegated to the <a href="trivial-rewrite.8.html"><b>triv-</b>
-       <b>ial-rewrite</b>(8)</a> daemon.  This program  expects  to  be  run
-       from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
-
-       Mail  addressed  to  the  local  <b>double-bounce</b>  address is
-       silently discarded.  This stops potential loops caused  by
-       undeliverable bounce notifications.
-
-       Mail  addressed to a user listed in the optional <b>relocated</b>
-       database is bounced with a "user has  moved  to  <i>new_loca-</i>
-       <i>tion</i>" message. See <a href="relocated.5.html"><b>relocated</b>(5)</a> for a precise description.
-
-<b>MAIL</b> <b>QUEUES</b>
-       The <b>nqmgr</b> daemon maintains the following queues:
-
-       <b>incoming</b>
-              Inbound mail from the network, or mail picked up by
-              the local <b>pickup</b> agent from the <b>maildrop</b> directory.
-
-       <b>active</b> Messages that the  queue  manager  has  opened  for
-              delivery.  Only  a  limited  number  of messages is
-              allowed to enter the  <b>active</b>  queue  (leaky  bucket
-              strategy, for a fixed delivery rate).
-
-       <b>deferred</b>
-              Mail  that  could  not  be delivered upon the first
-              attempt. The queue manager  implements  exponential
-              backoff  by  doubling  the  time  between  delivery
-              attempts.
-
-       <b>corrupt</b>
-              Unreadable or damaged queue files  are  moved  here
-              for inspection.
-
-<b>DELIVERY</b> <b>STATUS</b> <b>REPORTS</b>
-       The <b>nqmgr</b> daemon keeps an eye on per-message delivery sta-
-       tus reports in  the  following  directories.  Each  status
-       report file has the same name as the corresponding message
-       file:
-
-       <b>bounce</b> Per-recipient status information about why mail  is
-              bounced.    These   files  are  maintained  by  the
-              <a href="bounce.8.html"><b>bounce</b>(8)</a> daemon.
-
-       <b>defer</b>  Per-recipient status information about why mail  is
-
-
-
-                                                                1
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(8)
-
-
-              delayed.    These   files  are  maintained  by  the
-              <a href="defer.8.html"><b>defer</b>(8)</a> daemon.
-
-       The <b>nqmgr</b> daemon is responsible for asking  the  <a href="bounce.8.html"><b>bounce</b>(8)</a>
-       or <a href="defer.8.html"><b>defer</b>(8)</a> daemons to send non-delivery reports.
-
-<b>STRATEGIES</b>
-       The  queue  manager implements a variety of strategies for
-       either opening queue files (input) or for message delivery
-       (output).
-
-       <b>leaky</b> <b>bucket</b>
-              This  strategy limits the number of messages in the
-              <b>active</b> queue and prevents the  queue  manager  from
-              running out of memory under heavy load.
-
-       <b>fairness</b>
-              When  the  <b>active</b> queue has room, the queue manager
-              takes one message from the <b>incoming</b> queue  and  one
-              from the <b>deferred</b> queue. This prevents a large mail
-              backlog from blocking the delivery of new mail.
-
-       <b>slow</b> <b>start</b>
-              This strategy eliminates "thundering herd" problems
-              by slowly adjusting the number of parallel deliver-
-              ies to the same destination.
-
-       <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.
-
-       <b>exponential</b> <b>backoff</b>
-              Mail  that  cannot  be  delivered  upon  the  first
-              attempt is deferred.   The  time  interval  between
-              delivery attempts is doubled after each attempt.
-
-       <b>destination</b> <b>status</b> <b>cache</b>
-              The   queue  manager  avoids  unnecessary  delivery
-              attempts by  maintaining  a  short-term,  in-memory
-              list of unreachable destinations.
-
-       <b>preemptive</b> <b>message</b> <b>scheduling</b>
-              The  queue manager attempts to minimize the average
-              per-recipient delay while still preserving the cor-
-              rect per-message delays, using a sophisticated pre-
-              emptive message scheduling.
-
-<b>TRIGGERS</b>
-       On an idle system, the queue manager waits for the arrival
-       of  trigger  events,  or it waits for a timer to go off. A
-       trigger is a one-byte message.  Depending on  the  message
-       received,  the queue manager performs one of the following
-
-
-
-                                                                2
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(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
-              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>
-              Start  an incoming queue scan. If an incoming queue
-              scan is already in  progress,  that  scan  will  be
-              restarted as soon as it finishes.
-
-       <b>A</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>ALL)</b>
-              Ignore deferred queue file time stamps. The request
-              affects the next deferred queue scan.
-
-       <b>F</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>FLUSH</b><i>_</i><b>DEAD)</b>
-              Purge all information  about  dead  transports  and
-              destinations.
-
-       <b>W</b> <b>(TRIGGER</b><i>_</i><b>REQ</b><i>_</i><b>WAKEUP)</b>
-              Wakeup  call,  This is used by the master server to
-              instantiate servers that should not  go  away  for-
-              ever.  The  action  is  to  start an incoming queue
-              scan.
-
-       The <b>nqmgr</b> daemon reads an entire buffer worth of triggers.
-       Multiple  identical  trigger  requests  are collapsed into
-       one, and trigger requests are sorted so that <b>A</b> and <b>F</b>  pre-
-       cede  <b>D</b>  and  <b>I</b>.  Thus, in order to force a deferred queue
-       run, one would request <b>A</b> <b>F</b> <b>D</b>; in order to notify the queue
-       manager of the arrival of new mail one would request <b>I</b>.
-
-<b>STANDARDS</b>
-       None.  The <b>nqmgr</b> daemon does not interact with the outside
-       world.
-
-<b>SECURITY</b>
-       The <b>nqmgr</b> daemon is not security sensitive. It reads  sin-
-       gle-character  messages  from  untrusted  local users, and
-       thus may be susceptible to denial of service attacks.  The
-       <b>nqmgr</b>  daemon  does  not talk to the outside world, and it
-       can be run at fixed low privilege in a  chrooted  environ-
-       ment.
-
-<b>DIAGNOSTICS</b>
-       Problems and transactions are logged to the syslog daemon.
-       Corrupted message files are saved to the <b>corrupt</b> queue for
-       further inspection.
-
-       Depending  on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
-       the postmaster is notified of bounces and of  other  trou-
-       ble.
-
-
-
-                                                                3
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(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.
-
-<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>
-       command after a configuration change.
-
-<b>Miscellaneous</b>
-       <b>allow</b><i>_</i><b>min</b><i>_</i><b>user</b>
-              Do  not  bounce recipient addresses that begin with
-              '-'.
-
-       <b>relocated</b><i>_</i><b>maps</b>
-              Tables with contact information for users, hosts or
-              domains that no longer exist. See <a href="relocated.5.html"><b>relocated</b>(5)</a>.
-
-       <b>queue</b><i>_</i><b>directory</b>
-              Top-level directory of the Postfix queue.
-
-<b>Active</b> <b>queue</b> <b>controls</b>
-       In  the text below, <i>transport</i> is the first field in a <b>mas-</b>
-       <b>ter.cf</b> entry.
-
-       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>active</b><i>_</i><b>limit</b>
-              Limit the number of messages in the active queue.
-
-       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit the number of in-memory recipients.
-
-              This parameter also limits the size of  the  short-
-              term, in-memory destination cache.
-
-       <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>minimum</b>
-              Per message minimum of in-memory recipients.
-
-       <b>default</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Default limit on the number of in-memory recipients
-              per transport.
-
-       <i>transport_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit on the number of  in-memory  recipients,  for
-              the named message <i>transport</i>.
-
-       <b>default</b><i>_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Default  limit on the total number of per transport
-              in-memory recipients that the  preempting  messages
-              can have.
-
-
-
-
-
-                                                                4
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(8)
-
-
-       <i>transport_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  on  the number of in-memory recipients which
-              all preempting messages delivered by the  transport
-              <i>transport</i> can have.
-
-<b>Timing</b> <b>controls</b>
-       <b>min</b><i>_</i><b>backoff</b>
-              Minimal  time  in seconds between delivery attempts
-              of a deferred message.
-
-              This parameter also limits the time an  unreachable
-              destination  is  kept  in the short-term, in-memory
-              destination status cache.
-
-       <b>max</b><i>_</i><b>backoff</b>
-              Maximal time in seconds between  delivery  attempts
-              of a deferred message.
-
-       <b>maximal</b><i>_</i><b>queue</b><i>_</i><b>lifetime</b>
-              Maximal  time in days a message is queued before it
-              is sent back as undeliverable.
-
-       <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b>
-              Time in seconds between deferred queue scans. Queue
-              scans do not overlap.
-
-       <b>transport</b><i>_</i><b>retry</b><i>_</i><b>time</b>
-              Time  in seconds between attempts to contact a bro-
-              ken delivery transport.
-
-<b>Concurrency</b> <b>controls</b>
-       <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.
-
-       <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
-              Default  limit on the number of parallel deliveries
-              to the same destination.
-
-       <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
-              Limit on the number of parallel deliveries  to  the
-              same  destination,  for delivery via the named mes-
-              sage <i>transport</i>.
-
-<b>Recipient</b> <b>controls</b>
-       <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Default limit on the number of recipients per  mes-
-              sage transfer.
-
-       <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  on  the  number  of  recipients  per message
-              transfer, for the named message <i>transport</i>.
-
-
-
-
-
-                                                                5
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(8)
-
-
-<b>Message</b> <b>scheduling</b>
-       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b> (valid range: 0,2,3...)
-              This parameter basically controls how often a  mes-
-              sage  delivered  by  <i>transport</i>  can be preempted by
-              another message.  An internal per-message/transport
-              counter  is  incremented  by  one  for  each <i>trans-</i>
-              <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b>   deliveries   handled   by
-              <i>transport</i>.  This  counter  represents the number of
-              "available delivery slots" for use  by  other  mes-
-              sages.  Current message can be preempted by another
-              message when that other message  can  be  delivered
-              using  less  <i>transport</i> agents than the value of the
-              "available delivery slots" counter.
-
-              Value equal to 0 disables  the  message  preemption
-              for <i>transport</i>.
-
-       <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b>
-              Message preemption is not attempted at all whenever
-              a message  that  can't  ever  accumulate  at  least
-              <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b> available delivery
-              slots is being delivered by <i>transport</i>.
-
-       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> (valid range: 0..100)
-
-       <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>
-              These parameters speed up the moment when a message
-              preemption  can  happen.   Instead of waiting until
-              the full  amount  of  delivery  slots  required  is
-              available,  the  preemption  can happen when <i>trans-</i>
-              <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> percent of the required
-              amount   plus   <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>  still
-              remains to  be  accumulated.  Note  that  the  full
-              amount  will  still  have  to be accumulated before
-              another preemption can take place later.
-
-       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b>
-
-       <b>default</b><i>_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b>
-
-       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b>
-
-       <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b>
-              Default values for the transport  specific  parame-
-              ters described above.
-
-<b>SEE</b> <b>ALSO</b>
-       <a href="master.8.html">master(8)</a>, process manager
-       <a href="relocated.5.html">relocated(5)</a>, format of the "user has moved" table
-       syslogd(8) system logging
-       <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, address routing
-
-<b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
-
-
-
-                                                                6
-
-
-
-
-
-NQMGR(8)                                                 NQMGR(8)
-
-
-       software.
-
-<b>AUTHOR(S)</b>
-       Wietse Venema
-       IBM T.J. Watson Research
-       P.O. Box 704
-       Yorktown Heights, NY 10598, USA
-
-       Scheduler enhancements:
-       Patrik Rak
-       Modra 6
-       155 00, Prague, Czech Republic
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-                                                                7
-
-
-</pre> </body> </html>
index c81578a9b45c9872cdb612ec72980da104cfb515..a6fe58de545e39a604780385f2ae162a988611ef 100644 (file)
@@ -77,6 +77,11 @@ SMTPD(8)                                                 SMTPD(8)
               For  example, allow <a href="http://www.faqs.org/rfcs/rfc822.html">RFC822</a>-style address forms with
               comments, like Sendmail does.
 
+       <b>allow</b><i>_</i><b>broken</b><i>_</i><b>auth</b><i>_</i><b>clients</b>
+              Support older Microsoft clients that  mis-implement
+              the AUTH protocol, and that expect an EHLO response
+              of "250 AUTH=list" instead of "250 AUTH list".
+
 <b>Content</b> <b>inspection</b> <b>controls</b>
        <b>content</b><i>_</i><b>filter</b>
               The name of a mail delivery transport that  filters
@@ -119,11 +124,6 @@ SMTPD(8)                                                 SMTPD(8)
               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
-              host  matches  a  pattern  in  the  <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
-              parameter.
-
 
 
 
@@ -137,6 +137,11 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+       <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
+              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-
@@ -186,11 +191,6 @@ SMTPD(8)                                                 SMTPD(8)
               reject  responses.   This can be useful for testing
               purposes.
 
-<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
-              handling of partial input lines.
-
 
 
 
@@ -203,6 +203,11 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+<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
+              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.
@@ -253,11 +258,6 @@ SMTPD(8)                                                 SMTPD(8)
               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>
-              Restrict what domain names can be used in <b>ETRN</b> com-
-              mands, and what clients may issue <b>ETRN</b> commands.
-
-
 
 
                                                                 4
@@ -269,6 +269,10 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+       <b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b>
+              Restrict what domain names can be used in <b>ETRN</b> com-
+              mands, and what clients may issue <b>ETRN</b> commands.
+
        <b>allow</b><i>_</i><b>untrusted</b><i>_</i><b>routing</b>
               Allow  untrusted  clients to specify addresses with
               sender-specified routing.  Enabling this  opens  up
@@ -319,10 +323,6 @@ SMTPD(8)                                                 SMTPD(8)
               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
-              <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
-
 
 
 
@@ -335,6 +335,10 @@ SMTPD(8)                                                 SMTPD(8)
 SMTPD(8)                                                 SMTPD(8)
 
 
+       <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
+              <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
+
 <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
@@ -383,10 +387,6 @@ SMTPD(8)                                                 SMTPD(8)
 
 
 
-
-
-
-
 
 
 
diff --git a/postfix/html/virtual.8.html b/postfix/html/virtual.8.html
deleted file mode 100644 (file)
index 5f5aafb..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-<html> <head> </head> <body> <pre>
-
-
-
-VIRTUAL(8)                                             VIRTUAL(8)
-
-
-<b>NAME</b>
-       virtual - Postfix virtual domain mail delivery agent
-
-<b>SYNOPSIS</b>
-       <b>virtual</b> [generic Postfix daemon options]
-
-<b>DESCRIPTION</b>
-       This  daemon  is  designed for ISP's offering virtual mail
-       hosting services. Originally based on the  local  delivery
-       agent,  this  agent locates user mailboxes via map lookups
-       of the full recipient address, rather than hard-coded unix
-       password file searches of the local part only.
-
-       The  <b>virtual</b>  daemon  processes delivery requests from the
-       Postfix queue manager to deliver  mail  to  virtual  local
-       recipients.  Each delivery request specifies a queue file,
-       a sender address, a domain or host to deliver to, and  one
-       or  more  recipients.  This program expects to be run from
-       the <a href="master.8.html"><b>master</b>(8)</a> process manager.
-
-       The <b>virtual</b> daemon updates queue files and  marks  recipi-
-       ents  as  finished,  or  it informs the queue manager that
-       delivery should be tried again at a later  time.  Delivery
-       problem reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a> or <a href="defer.8.html"><b>defer</b>(8)</a> dae-
-       mon as appropriate.
-
-<b>MAILBOX</b> <b>DELIVERY</b>
-       The <b>virtual</b> delivery agent can deliver to UNIX-style mail-
-       box file or to qmail-style maildir files. The pathname and
-       delivery mailbox style are controlled by the <b>virtual</b><i>_</i><b>mail-</b>
-       <b>box</b><i>_</i><b>base</b> and <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps</b> configuration parameters
-       (see below).
-
-       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
-       and prepends  a  <b>Return-Path:</b>  header  with  the  envelope
-       sender address.
-
-<b>DELIVERY</b> <b>RIGHTS</b>
-       Deliveries  are  made  with  the user and group privileges
-       that are listed in the  tables  specified  with  the  <b>vir-</b>
-       <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> and <b>virtual</b><i>_</i><b>gid</b><i>_</i><b>maps</b>, respectively.
-
-       The  <b>virtual</b><i>_</i><b>minimum</b><i>_</i><b>uid</b> parameter specifies a lower bound
-
-
-
-                                                                1
-
-
-
-
-
-VIRTUAL(8)                                             VIRTUAL(8)
-
-
-       on  user  ID  values  that  may  be  specified   in   <b>vir-</b>
-       <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b>.  Mail  will not be delivered when a too low
-       UID value is found.
-
-<b>STANDARDS</b>
-       <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
-
-<b>DIAGNOSTICS</b>
-       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 afterwards.
-
-       Depending on the setting of the <b>notify</b><i>_</i><b>classes</b>  parameter,
-       the  postmaster  is notified of bounces and of other trou-
-       ble.
-
-<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>
-       command after a configuration change.
-
-<b>Mailbox</b> <b>delivery</b>
-       <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base</b>
-              Specifies  a  path that is prepended to all mailbox
-              or maildir paths.  This  is  a  safety  measure  to
-              ensure  that an out of control map in <b>virtual</b><i>_</i><b>mail-</b>
-              <b>box</b><i>_</i><b>maps</b> doesn't litter the filesystem  with  mail-
-              boxes.   While it could be set to "/", this setting
-              isn't recommended.
-
-       <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps</b>
-              Recipients are looked up in this map  to  determine
-              the  path  to  their  mailbox  or  maildir.  If the
-              returned path ends in a slash ("/"),  maildir-style
-              delivery  is  carried  out,  otherwise  the path is
-              assumed to specify a mailbox file.
-
-              Note that <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base</b>  is  unconditionally
-              prepended to this path.
-
-       <b>virtual</b><i>_</i><b>minimum</b><i>_</i><b>uid</b>
-              Specifies  a minimum uid that will be accepted as a
-              return from  a  <b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b>  lookup.  Returned
-              values  less  than  this  will be rejected, and the
-              message will be deferred.
-
-       <b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b>
-              Recipients are looked up in this map  to  determine
-              the UID to be used when writing to the target mail-
-              box.
-
-       <b>virtual</b><i>_</i><b>gid</b><i>_</i><b>maps</b>
-              Recipients are looked up in this map  to  determine
-
-
-
-                                                                2
-
-
-
-
-
-VIRTUAL(8)                                             VIRTUAL(8)
-
-
-              the GID to be used when writing to the target mail-
-              box.
-
-<b>Locking</b> <b>controls</b>
-       <b>mailbox</b><i>_</i><b>delivery</b><i>_</i><b>lock</b>
-              How to lock UNIX-style mailboxes: one  or  more  of
-              <b>flock</b>, <b>fcntl</b> or <b>dotlock</b>.
-
-              Use  the command <b>postconf</b> <b>-m</b> to find out what lock-
-              ing methods are available on your system.
-
-       <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
-              Limit the number of attempts to acquire  an  exclu-
-              sive lock on a mailbox file.
-
-       <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
-              Time (default: seconds) between successive attempts
-              to acquire an exclusive lock on a mailbox file.
-
-       <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
-              Limit the time after  which  a  stale  lockfile  is
-              removed.
-
-<b>Resource</b> <b>controls</b>
-       <b>virtual</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
-              domain.   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>virtual</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
-              <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
-
-<b>HISTORY</b>
-       This  agent  was  originally  based  on the local delivery
-       agent. Modifications mainly  consisted  of  removing  code
-       that  wasn't  applicable  or  wasn't  safe in this context
-       (aliases, .forwards, program aliases).
-
-       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
-       Daniel Bernstein.
-
-<b>SEE</b> <b>ALSO</b>
-       <a href="bounce.8.html">bounce(8)</a> non-delivery status reports
-       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.
-
-
-
-                                                                3
-
-
-
-
-
-VIRTUAL(8)                                             VIRTUAL(8)
-
-
-<b>AUTHOR(S)</b>
-       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 2060, NSW, Australia
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-                                                                4
-
-
-</pre> </body> </html>
index 8ea0fe0fd76d8713d294da761e25d88423c35f2b..70b4d98176974450515e6acbaeac454b451bd2ad 100644 (file)
@@ -5,7 +5,7 @@ SHELL   = /bin/sh
 DAEMONS        = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
        man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
        man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
-       man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8
+       man8/spawn.8 man8/flush.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 \
@@ -50,12 +50,6 @@ man8/lmtp.8: ../src/lmtp/lmtp.c
 man8/master.8: ../src/master/master.c
        ../mantools/srctoman $? >$@
 
-man8/nqmgr.8: ../src/nqmgr/qmgr.c
-       ../mantools/srctoman $? | \
-               sed -e 's/qmgr[^_]/n&/' \
-                   -e 's/qmgr$$/n&/' \
-                   -e 's/QMGR[^_]/N&/' >$@
-
 man8/pickup.8: ../src/pickup/pickup.c
        ../mantools/srctoman $? >$@
 
@@ -80,9 +74,6 @@ man8/smtpd.8: ../src/smtpd/smtpd.c
 man8/trivial-rewrite.8: ../src/trivial-rewrite/trivial-rewrite.c
        ../mantools/srctoman $? >$@
 
-man8/virtual.8: ../src/virtual/virtual.c
-       ../mantools/srctoman $? >$@
-
 man1/postalias.1: ../src/postalias/postalias.c
        ../mantools/srctoman $? >$@
 
diff --git a/postfix/man/man8/nqmgr.8 b/postfix/man/man8/nqmgr.8
deleted file mode 100644 (file)
index 4a36d1d..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-.TH NQMGR 8 
-.ad
-.fi
-.SH NAME
-nqmgr
-\-
-Postfix queue manager
-.SH SYNOPSIS
-.na
-.nf
-\fBnqmgr\fR [generic Postfix daemon options]
-.SH DESCRIPTION
-.ad
-.fi
-The \fBnqmgr\fR daemon awaits the arrival of incoming mail
-and arranges for its delivery via Postfix delivery processes.
-The actual mail routing strategy is delegated to the
-\fBtrivial-rewrite\fR(8) daemon.
-This program expects to be run from the \fBmaster\fR(8) process
-manager.
-
-Mail addressed to the local \fBdouble-bounce\fR address is silently
-discarded.  This stops potential loops caused by undeliverable
-bounce notifications.
-
-Mail addressed to a user listed in the optional \fBrelocated\fR
-database is bounced with a "user has moved to \fInew_location\fR"
-message. See \fBrelocated\fR(5) for a precise description.
-.SH MAIL QUEUES
-.na
-.nf
-.ad
-.fi
-The \fBnqmgr\fR daemon maintains the following queues:
-.IP \fBincoming\fR
-Inbound mail from the network, or mail picked up by the
-local \fBpickup\fR agent from the \fBmaildrop\fR directory.
-.IP \fBactive\fR
-Messages that the queue manager has opened for delivery. Only
-a limited number of messages is allowed to enter the \fBactive\fR
-queue (leaky bucket strategy, for a fixed delivery rate).
-.IP \fBdeferred\fR
-Mail that could not be delivered upon the first attempt. The queue
-manager implements exponential backoff by doubling the time between
-delivery attempts.
-.IP \fBcorrupt\fR
-Unreadable or damaged queue files are moved here for inspection.
-.SH DELIVERY STATUS REPORTS
-.na
-.nf
-.ad
-.fi
-The \fBnqmgr\fR daemon keeps an eye on per-message delivery status
-reports in the following directories. Each status report file has
-the same name as the corresponding message file:
-.IP \fBbounce\fR
-Per-recipient status information about why mail is bounced.
-These files are maintained by the \fBbounce\fR(8) daemon.
-.IP \fBdefer\fR
-Per-recipient status information about why mail is delayed.
-These files are maintained by the \fBdefer\fR(8) daemon.
-.PP
-The \fBnqmgr\fR daemon is responsible for asking the
-\fBbounce\fR(8) or \fBdefer\fR(8) daemons to send non-delivery
-reports.
-.SH STRATEGIES
-.na
-.nf
-.ad
-.fi
-The queue manager implements a variety of strategies for
-either opening queue files (input) or for message delivery (output).
-.IP "\fBleaky bucket\fR"
-This strategy limits the number of messages in the \fBactive\fR queue
-and prevents the queue manager from running out of memory under
-heavy load.
-.IP \fBfairness\fR
-When the \fBactive\fR queue has room, the queue manager takes one
-message from the \fBincoming\fR queue and one from the \fBdeferred\fR
-queue. This prevents a large mail backlog from blocking the delivery
-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
-The queue manager sorts delivery requests by destination.
-Round-robin selection prevents one destination from dominating
-deliveries to other destinations.
-.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
-attempt.
-.IP "\fBdestination status cache\fR"
-The queue manager avoids unnecessary delivery attempts by
-maintaining a short-term, in-memory list of unreachable destinations.
-.IP "\fBpreemptive message scheduling\fR"
-The queue manager attempts to minimize the average per-recipient delay
-while still preserving the correct per-message delays, using
-a sophisticated preemptive message scheduling.
-.SH TRIGGERS
-.na
-.nf
-.ad
-.fi
-On an idle system, the queue manager waits for the arrival of
-trigger events, or it waits for a timer to go off. A trigger
-is a one-byte message.
-Depending on the message received, the queue manager performs
-one of the following actions (the message is followed by the
-symbolic constant used internally by the software):
-.IP "\fBD (QMGR_REQ_SCAN_DEFERRED)\fR"
-Start a deferred queue scan.  If a deferred queue scan is already
-in progress, that scan will be restarted as soon as it finishes.
-.IP "\fBI (QMGR_REQ_SCAN_INCOMING)\fR"
-Start an incoming queue scan. If an incoming queue scan is already
-in progress, that scan will be restarted as soon as it finishes.
-.IP "\fBA (QMGR_REQ_SCAN_ALL)\fR"
-Ignore deferred queue file time stamps. The request affects
-the next deferred queue scan.
-.IP "\fBF (QMGR_REQ_FLUSH_DEAD)\fR"
-Purge all information about dead transports and destinations.
-.IP "\fBW (TRIGGER_REQ_WAKEUP)\fR"
-Wakeup call, This is used by the master server to instantiate
-servers that should not go away forever. The action is to start
-an incoming queue scan.
-.PP
-The \fBnqmgr\fR daemon reads an entire buffer worth of triggers.
-Multiple identical trigger requests are collapsed into one, and
-trigger requests are sorted so that \fBA\fR and \fBF\fR precede
-\fBD\fR and \fBI\fR. Thus, in order to force a deferred queue run,
-one would request \fBA F D\fR; in order to notify the queue manager
-of the arrival of new mail one would request \fBI\fR.
-.SH STANDARDS
-.na
-.nf
-.ad
-.fi
-None. The \fBnqmgr\fR daemon does not interact with the outside world.
-.SH SECURITY
-.na
-.nf
-.ad
-.fi
-The \fBnqmgr\fR daemon is not security sensitive. It reads
-single-character messages from untrusted local users, and thus may
-be susceptible to denial of service attacks. The \fBnqmgr\fR daemon
-does not talk to the outside world, and it can be run at fixed low
-privilege in a chrooted environment.
-.SH DIAGNOSTICS
-.ad
-.fi
-Problems and transactions are logged to the syslog daemon.
-Corrupted message files are saved to the \fBcorrupt\fR queue
-for further inspection.
-
-Depending on the setting of the \fBnotify_classes\fR parameter,
-the postmaster is notified of bounces and of other trouble.
-.SH BUGS
-.ad
-.fi
-A single queue manager process has to compete for disk access with
-multiple front-end processes such as \fBsmtpd\fR. A sudden burst of
-inbound mail can negatively impact outbound delivery rates.
-.SH CONFIGURATION PARAMETERS
-.na
-.nf
-.ad
-.fi
-The following \fBmain.cf\fR parameters are especially relevant to
-this program. See the Postfix \fBmain.cf\fR file for syntax details
-and for default values. Use the \fBpostfix reload\fR command after
-a configuration change.
-.SH Miscellaneous
-.ad
-.fi
-.IP \fBallow_min_user\fR
-Do not bounce recipient addresses that begin with '-'.
-.IP \fBrelocated_maps\fR
-Tables with contact information for users, hosts or domains
-that no longer exist. See \fBrelocated\fR(5).
-.IP \fBqueue_directory\fR
-Top-level directory of the Postfix queue.
-.SH "Active queue controls"
-.ad
-.fi
-In the text below, \fItransport\fR is the first field in a
-\fBmaster.cf\fR entry.
-.IP \fBqmgr_message_active_limit\fR
-Limit the number of messages in the active queue.
-.IP \fBqmgr_message_recipient_limit\fR
-Limit the number of in-memory recipients.
-.sp
-This parameter also limits the size of the short-term, in-memory
-destination cache.
-.IP \fBqmgr_message_recipient_minimum\fR
-Per message minimum of in-memory recipients.
-.IP \fBdefault_recipient_limit\fR
-Default limit on the number of in-memory recipients per transport.
-.IP \fItransport\fB_recipient_limit\fR
-Limit on the number of in-memory recipients, for the named
-message \fItransport\fR.
-.IP \fBdefault_extra_recipient_limit\fR
-Default limit on the total number of per transport in-memory
-recipients that the preempting messages can have.
-.IP \fItransport\fB_extra_recipient_limit\fR
-Limit on the number of in-memory recipients which all preempting
-messages delivered by the transport \fItransport\fR can have.
-.SH "Timing controls"
-.ad
-.fi
-.IP \fBmin_backoff\fR
-Minimal time in seconds between delivery attempts
-of a deferred message.
-.sp
-This parameter also limits the time an unreachable destination
-is kept in the short-term, in-memory destination status cache.
-.IP \fBmax_backoff\fR
-Maximal time in seconds between delivery attempts
-of a deferred message.
-.IP \fBmaximal_queue_lifetime\fR
-Maximal time in days a message is queued
-before it is sent back as undeliverable.
-.IP \fBqueue_run_delay\fR
-Time in seconds between deferred queue scans. Queue scans do
-not overlap.
-.IP \fBtransport_retry_time\fR
-Time in seconds between attempts to contact a broken
-delivery transport.
-.SH "Concurrency controls"
-.ad
-.fi
-.IP \fBinitial_destination_concurrency\fR
-Initial per-destination concurrency level for parallel delivery
-to the same destination.
-.IP \fBdefault_destination_concurrency_limit\fR
-Default limit on the number of parallel deliveries to the same
-destination.
-.IP \fItransport\fB_destination_concurrency_limit\fR
-Limit on the number of parallel deliveries to the same destination,
-for delivery via the named message \fItransport\fR.
-.SH "Recipient controls"
-.ad
-.fi
-.IP \fBdefault_destination_recipient_limit\fR
-Default limit on the number of recipients per message transfer.
-.IP \fItransport\fB_destination_recipient_limit\fR
-Limit on the number of recipients per message transfer, for the
-named message \fItransport\fR.
-.SH "Message scheduling"
-.ad
-.fi
-.IP "\fItransport\fB_delivery_slot_cost\fR (valid range: 0,2,3...)
-This parameter basically controls how often a message
-delivered by \fItransport\fR can be preempted by another
-message.
-An internal per-message/transport counter is incremented by one
-for each \fItransport\fB_delivery_slot_cost\fR
-deliveries handled by \fItransport\fR. This counter represents
-the number of "available delivery slots" for use by other messages.
-Current message can be preempted by another message when that
-other message can be delivered using less \fItransport\fR agents
-than the value of the "available delivery slots" counter.
-.sp
-Value equal to 0 disables the message preemption for \fItransport\fR.
-.IP \fItransport\fB_minimum_delivery_slots\fR
-Message preemption is not attempted at all whenever a message
-that can't ever accumulate at least \fItransport\fB_minimum_delivery_slots\fR
-available delivery slots is being delivered by \fItransport\fR.
-.IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)"
-.IP \fItransport\fB_delivery_slot_loan\fR
-These parameters speed up the moment when a message preemption can happen.
-Instead of waiting until the full amount of delivery slots
-required is available, the preemption can happen when
-\fItransport\fB_delivery_slot_discount\fR percent of the required
-amount plus \fItransport\fB_delivery_slot_loan\fR still remains to
-be accumulated. Note that the full amount will still have to be
-accumulated before another preemption can take place later.
-.IP \fBdefault_delivery_slot_cost\fR
-.IP \fBdefault_minimum_delivery_slots\fR
-.IP \fBdefault_delivery_slot_discount\fR
-.IP \fBdefault_delivery_slot_loan\fR
-Default values for the transport specific parameters described above.
-.SH SEE ALSO
-.na
-.nf
-master(8), process manager
-relocated(5), format of the "user has moved" table
-syslogd(8) system logging
-trivial-rewrite(8), address routing
-.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
-
-Scheduler enhancements:
-Patrik Rak
-Modra 6
-155 00, Prague, Czech Republic
index 832e3e19db3482fad3474d3a28a2b46331637eaa..f8eccc0cb5ac70e8f3241e71679f84e79d6462aa 100644 (file)
@@ -71,6 +71,10 @@ a configuration change.
 .IP \fBstrict_rfc821_envelopes\fR
 Disallow non-RFC 821 style addresses in envelopes. For example,
 allow RFC822-style address forms with comments, like Sendmail does.
+.IP \fBallow_broken_auth_clients\fR
+Support older Microsoft clients that mis-implement the AUTH
+protocol, and that expect an EHLO response of "250 AUTH=list"
+instead of "250 AUTH list".
 .SH "Content inspection controls"
 .IP \fBcontent_filter\fR
 The name of a mail delivery transport that filters mail and that
diff --git a/postfix/man/man8/virtual.8 b/postfix/man/man8/virtual.8
deleted file mode 100644 (file)
index 79849c3..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-.TH VIRTUAL 8 
-.ad
-.fi
-.SH NAME
-virtual
-\-
-Postfix virtual domain mail delivery agent
-.SH SYNOPSIS
-.na
-.nf
-\fBvirtual\fR [generic Postfix daemon options]
-.SH DESCRIPTION
-.ad
-.fi
-This daemon is designed for ISP's offering virtual mail hosting
-services. Originally based on the local delivery agent, this agent
-locates user mailboxes via map lookups of the full recipient
-address, rather than hard-coded unix password file searches of
-the local part only.
-
-The \fBvirtual\fR daemon processes delivery requests from the
-Postfix queue manager to deliver mail to virtual local recipients.
-Each delivery request specifies a queue file, a sender address,
-a domain or host to deliver to, and one or more recipients.
-This program expects to be run from the \fBmaster\fR(8) process
-manager.
-
-The \fBvirtual\fR daemon updates queue files and marks recipients
-as finished, or it informs the queue manager that delivery should
-be tried again at a later time. Delivery problem reports are sent
-to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
-.SH MAILBOX DELIVERY
-.na
-.nf
-.ad
-.fi
-The \fBvirtual\fR delivery agent can deliver to UNIX-style mailbox
-file or to qmail-style maildir files. The pathname and delivery
-mailbox style are controlled by the \fBvirtual_mailbox_base\fR
-and \fBvirtual_mailbox_maps\fR configuration parameters (see below).
-
-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 \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
-and prepends a \fBReturn-Path:\fR header with the envelope sender
-address.
-.SH DELIVERY RIGHTS
-.na
-.nf
-.ad
-.fi
-Deliveries are made with the user and group privileges that are
-listed in the tables specified with the \fBvirtual_uid_maps\fR
-and \fBvirtual_gid_maps\fR, respectively.
-
-The \fBvirtual_minimum_uid\fR parameter specifies a lower bound on
-user ID values that may be specified in \fBvirtual_uid_maps\fR. Mail
-will not be delivered when a too low UID value is found.
-.SH STANDARDS
-.na
-.nf
-RFC 822 (ARPA Internet Text Messages)
-.SH DIAGNOSTICS
-.ad
-.fi
-Problems and transactions are logged to \fBsyslogd\fR(8).
-Corrupted message files are marked so that the queue
-manager can move them to the \fBcorrupt\fR queue afterwards.
-
-Depending on the setting of the \fBnotify_classes\fR parameter,
-the postmaster is notified of bounces and of other trouble.
-.SH CONFIGURATION PARAMETERS
-.na
-.nf
-.ad
-.fi
-The following \fBmain.cf\fR parameters are especially relevant to
-this program. See the Postfix \fBmain.cf\fR file for syntax details
-and for default values. Use the \fBpostfix reload\fR command after
-a configuration change.
-.SH Mailbox delivery
-.ad
-.fi
-.IP \fBvirtual_mailbox_base\fR
-Specifies a path that is prepended to all mailbox or maildir paths.
-This is a safety measure to ensure that an out of control map in
-\fBvirtual_mailbox_maps\fR doesn't litter the filesystem with mailboxes.
-While it could be set to "/", this setting isn't recommended.
-.IP \fBvirtual_mailbox_maps\fR
-Recipients are looked up in this map to determine the path to
-their mailbox or maildir. If the returned path ends in a slash
-("/"), maildir-style delivery is carried out, otherwise the
-path is assumed to specify a mailbox file.
-
-Note that \fBvirtual_mailbox_base\fR is unconditionally prepended
-to this path.
-.IP \fBvirtual_minimum_uid\fR
-Specifies a minimum uid that will be accepted as a return from
-a \fBvirtual_uid_maps\fR lookup. Returned values less than this
-will be rejected, and the message will be deferred.
-.IP \fBvirtual_uid_maps\fR
-Recipients are looked up in this map to determine the UID to be
-used when writing to the target mailbox.
-.IP \fBvirtual_gid_maps\fR
-Recipients are looked up in this map to determine the GID to be
-used when writing to the target mailbox.
-.SH "Locking controls"
-.ad
-.fi
-.IP \fBmailbox_delivery_lock\fR
-How to lock UNIX-style mailboxes: one or more of \fBflock\fR,
-\fBfcntl\fR or \fBdotlock\fR.
-
-Use the command \fBpostconf -m\fR to find out what locking methods
-are available on your system.
-.IP \fBdeliver_lock_attempts\fR
-Limit the number of attempts to acquire an exclusive lock
-on a mailbox file.
-.IP \fBdeliver_lock_delay\fR
-Time (default: seconds) between successive attempts to acquire
-an exclusive lock on a mailbox file.
-.IP \fBstale_lock_time\fR
-Limit the time after which a stale lockfile is removed.
-.SH "Resource controls"
-.ad
-.fi
-.IP \fBvirtual_destination_concurrency_limit\fR
-Limit the number of parallel deliveries to the same domain.
-The default limit is taken from the
-\fBdefault_destination_concurrency_limit\fR parameter.
-.IP \fBvirtual_destination_recipient_limit\fR
-Limit the number of recipients per message delivery.
-The default limit is taken from the
-\fBdefault_destination_recipient_limit\fR parameter.
-.SH HISTORY
-.na
-.nf
-.ad
-.fi
-This agent was originally based on the local delivery
-agent. Modifications mainly consisted of removing code that wasn't
-applicable or wasn't safe in this context (aliases, .forwards,
-program aliases).
-
-The \fBDelivered-To:\fR header appears in the \fBqmail\fR system
-by Daniel Bernstein.
-
-The \fImaildir\fR structure appears in the \fBqmail\fR system
-by Daniel Bernstein.
-.SH SEE ALSO
-.na
-.nf
-bounce(8) non-delivery status reports
-syslogd(8) system logging
-qmgr(8) queue manager
-.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
-
-Andrew McNamara
-andrewm@connect.com.au
-connect.com.au Pty. Ltd.
-Level 3, 213 Miller St
-North Sydney 2060, NSW, Australia
diff --git a/postfix/src/base64/.indent.pro b/postfix/src/base64/.indent.pro
deleted file mode 120000 (symlink)
index 5c837ec..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/base64/Makefile.in b/postfix/src/base64/Makefile.in
deleted file mode 100644 (file)
index 08a2e49..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-SHELL  = /bin/sh
-SRCS   = base64encode.c base64decode.c
-OBJS   = base64encode.o base64decode.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= 
-INC_DIR        = ../../include
-PROG   = base64encode base64decode
-LIBS   = ../../lib/libglobal.a ../../lib/libutil.a
-
-.c.o:; $(CC) $(CFLAGS) -c $*.c
-
-all:   $(PROG)
-
-Makefile: Makefile.in
-       (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
-
-base64decode: base64decode.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ base64decode.o $(LIBS) $(SYSLIBS)
-
-base64encode: base64encode.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ base64encode.o $(LIBS) $(SYSLIBS)
-
-test:  $(TESTPROG)
-
-update: ../../bin/base64encode ../../bin/base64decode
-
-../../bin/base64encode: base64encode
-       cp $? $@
-
-../../bin/base64decode: base64decode
-       cp $? $@
-
-printfck: $(OBJS) $(PROG)
-       rm -rf printfck
-       mkdir printfck
-       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
-       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
-       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
-
-lint:
-       lint $(DEFS) $(SRCS) $(LINTFIX)
-
-clean:
-       rm -f *.o *core $(PROG) $(TESTPROG) junk
-       rm -rf printfck
-
-tidy:  clean
-
-depend: $(MAKES)
-       (sed '1,/^# do not edit/!d' Makefile.in; \
-       set -e; for i in [a-z][a-z0-9]*.c; do \
-           $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
-           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
-       done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
-       @$(EXPORT) make -f Makefile.in Makefile 1>&2
-
-# do not edit below this line - it is generated by 'make depend'
-base64decode.o: base64decode.c
-base64decode.o: ../../include/sys_defs.h
-base64decode.o: ../../include/vstring.h
-base64decode.o: ../../include/vbuf.h
-base64decode.o: ../../include/vstream.h
-base64decode.o: ../../include/vstring_vstream.h
-base64decode.o: ../../include/msg.h
-base64decode.o: ../../include/msg_vstream.h
-base64encode.o: base64encode.c
-base64encode.o: ../../include/sys_defs.h
-base64encode.o: ../../include/vstring.h
-base64encode.o: ../../include/vbuf.h
-base64encode.o: ../../include/vstream.h
-base64encode.o: ../../include/vstring_vstream.h
-base64encode.o: ../../include/msg.h
-base64encode.o: ../../include/msg_vstream.h
diff --git a/postfix/src/base64/base64decode.c b/postfix/src/base64/base64decode.c
deleted file mode 100644 (file)
index 14602ad..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* base64decode - transform base 64 data to printable form */
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <ctype.h>
-
-/* SASL library. */
-
-#include <sasl.h>
-#include <saslutil.h>
-
-/* Utility library. */
-
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <msg.h>
-#include <msg_vstream.h>
-
-/* Application-specific. */
-
-#define STR(x) vstring_str(x)
-#define LEN(x) VSTRING_LEN(x)
-
-#define UCHAR(x) ((unsigned char *) (x))
-
-static VSTRING *escape(VSTRING *escaped, char *input, int len)
-{
-    char   *cp;
-    unsigned ch;
-
-    VSTRING_RESET(escaped);
-    for (cp = input; cp < input + len; cp++) {
-       ch = *UCHAR(cp);
-       if (ISASCII(ch) && ISPRINT(ch))
-           VSTRING_ADDCH(escaped, ch);
-       else
-           vstring_sprintf_append(escaped, "\\%03o", ch);
-    }
-    VSTRING_TERMINATE(escaped);
-    return (escaped);
-}
-
-int     main(int unused_argc, char **argv)
-{
-    VSTRING *input = vstring_alloc(100);
-    VSTRING *escaped = vstring_alloc(100);
-    VSTRING *result = vstring_alloc(100);
-    int     len;
-
-    msg_vstream_init(argv[0], VSTREAM_ERR);
-
-    while (vstring_get_nonl(input, VSTREAM_IN) != VSTREAM_EOF) {
-       VSTRING_SPACE(result, LEN(input));
-       if (sasl_decode64(STR(input), LEN(input),
-                         STR(result), &len) != SASL_OK)
-           msg_fatal("malformed input");
-       vstream_printf("%s\n", STR(escape(escaped, STR(result), len)));
-       vstream_fflush(VSTREAM_OUT);
-    }
-    return (0);
-}
diff --git a/postfix/src/base64/base64encode.c b/postfix/src/base64/base64encode.c
deleted file mode 100644 (file)
index 73ee0dc..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* base64encode - transform printable form to base 64 data */
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <ctype.h>
-
-/* SASL library. */
-
-#include <sasl.h>
-#include <saslutil.h>
-
-/* Utility library. */
-
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <msg.h>
-#include <msg_vstream.h>
-
-/* Application-specific. */
-
-#define STR(x) vstring_str(x)
-#define LEN(x) VSTRING_LEN(x)
-
-#define UCHAR(x) ((unsigned char *) (x))
-
-static VSTRING *unescape(VSTRING *unescaped, VSTRING *input)
-{
-    char   *cp = STR(input);
-    int     ch;
-    int     oval;
-    int     i;
-
-    VSTRING_RESET(unescaped);
-    while ((ch = *UCHAR(cp++)) != 0) {
-       switch (ch) {
-       case '\\':
-           for (oval = 0, i = 0; i < 3 && (ch = *UCHAR(cp)) != 0; i++) {
-               if (!ISDIGIT(ch) || ch == '8' || ch == '9')
-                   break;
-               oval = (oval << 3) | (ch - '0');
-               cp++;
-           }
-           VSTRING_ADDCH(unescaped, oval);
-           break;
-       default:
-           VSTRING_ADDCH(unescaped, ch);
-           break;
-       }
-    }
-    VSTRING_TERMINATE(unescaped);
-    return (unescaped);
-}
-
-int     main(int unused_argc, char **argv)
-{
-    VSTRING *input = vstring_alloc(100);
-    VSTRING *unescaped = vstring_alloc(100);
-    VSTRING *result = vstring_alloc(100);
-    int     result_len;
-    int     len;
-
-    msg_vstream_init(argv[0], VSTREAM_ERR);
-
-    while (vstring_get_nonl(input, VSTREAM_IN) != VSTREAM_EOF) {
-       unescape(unescaped, input);
-       result_len = ((LEN(unescaped) + 2) / 3) * 4 + 1;
-       VSTRING_SPACE(result, result_len);
-       if (sasl_encode64(STR(unescaped), LEN(unescaped), STR(result),
-                         result_len, &len) != SASL_OK)
-           msg_panic("sasl_encode64 botch");
-       vstream_printf("%.*s\n", len, STR(result));
-       vstream_fflush(VSTREAM_OUT);
-    }
-    return (0);
-}
index b31a1e8f5e92e97ef2baaa0a00bb525eddd0d554..cc5e15f6bf06afd3d8f59e4f370aceac876e2fe6 100644 (file)
@@ -339,10 +339,10 @@ int     bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
                        "####################################################################");
        post_mail_fputs(bounce, "");
        post_mail_fprintf(bounce,
-                       "Your message could not be delivered for %.1g hours.",
+                       "Your message could not be delivered for %.1f hours.",
                          var_delay_warn_time / 3600.0);
        post_mail_fprintf(bounce,
-                         "It will be retried until it is %.1g days old.",
+                         "It will be retried until it is %.1f days old.",
                          var_max_queue_time / 86400.0);
     }
 
index 8ff8a2a196084c197cc333bc1385733386afc144..559e89ac452ec2dcfc73bbba92274c67c70d4e78 100644 (file)
@@ -237,6 +237,14 @@ extern char *var_rcpt_witheld;
 #define DEF_STRICT_RFC821_ENV  0
 extern bool var_strict_rfc821_env;
 
+ /*
+  * Standards violation: send "250 AUTH=list" in order to accomodate broken
+  * Microsoft clients.
+  */
+#define VAR_BROKEN_AUTH_CLNTS  "allow_broken_auth_clients"
+#define DEF_BROKEN_AUTH_CLNTS  0
+extern bool var_broken_auth_clients;
+
  /*
   * Standards violation: disable VRFY.
   */
@@ -712,7 +720,7 @@ extern int var_smtpd_err_sleep;
 extern int var_smtpd_junk_cmd_limit;
 
  /*
-  * SASL authentication support, server side.
+  * SASL authentication support, SMTP server side.
   */
 #define VAR_SMTPD_SASL_ENABLE  "smtpd_sasl_auth_enable"
 #define DEF_SMTPD_SASL_ENABLE  0
@@ -727,7 +735,7 @@ extern char *var_smtpd_sasl_opts;
 extern char *var_smtpd_sasl_realm;
 
  /*
-  * SASL authentication support, client side.
+  * SASL authentication support, SMTP client side.
   */
 #define VAR_SMTP_SASL_ENABLE   "smtp_sasl_auth_enable"
 #define DEF_SMTP_SASL_ENABLE   0
@@ -741,6 +749,24 @@ extern char *var_smtp_sasl_passwd;
 #define DEF_SMTP_SASL_OPTS     "noplaintext, noanonymous"
 extern char *var_smtp_sasl_opts;
 
+ /*
+  * SASL authentication support, LMTP client side.
+  */
+#define VAR_LMTP_SASL_ENABLE   "lmtp_sasl_auth_enable"
+#define DEF_LMTP_SASL_ENABLE   0
+extern bool var_lmtp_sasl_enable;
+
+#define VAR_LMTP_SASL_PASSWD   "lmtp_sasl_password_maps"
+#define DEF_LMTP_SASL_PASSWD   ""
+extern char *var_lmtp_sasl_passwd;
+
+#define VAR_LMTP_SASL_OPTS     "lmtp_sasl_security_options"
+#define DEF_LMTP_SASL_OPTS     "noplaintext, noanonymous"
+extern char *var_lmtp_sasl_opts;
+
+ /*
+  * SASL-based relay etc. control.
+  */
 #define PERMIT_SASL_AUTH       "permit_sasl_authenticated"
 
  /*
@@ -1110,18 +1136,23 @@ extern char *var_export_environ;
 #define VAR_VIRT_MAILBOX_MAPS  "virtual_mailbox_maps"
 #define DEF_VIRT_MAILBOX_MAPS  ""
 extern char *var_mailbox_maps;
+
 #define VAR_VIRT_UID_MAPS      "virtual_uid_maps"
 #define DEF_VIRT_UID_MAPS      ""
 extern char *var_uid_maps;
+
 #define VAR_VIRT_GID_MAPS      "virtual_gid_maps"
 #define DEF_VIRT_GID_MAPS      ""
 extern char *var_gid_maps;
+
 #define VAR_VIRT_USEDOTLOCK    "virtual_usedotlock"
 #define DEF_VIRT_USEDOTLOCK    0
 extern bool var_virt_usedotlock;
+
 #define VAR_VIRT_MINUID                "virtual_minimum_uid"
 #define DEF_VIRT_MINUID                100
-extern int  var_virt_minimum_uid;
+extern int var_virt_minimum_uid;
+
 #define VAR_VIRT_MAILBOX_BASE  "virtual_mailbox_base"
 #define DEF_VIRT_MAILBOX_BASE  ""
 extern char *var_virt_mailbox_base;
index 23e18cccc1ba7053518cc2283f022c834363a6a6..cca871749692444de00b1870911d9bdc058c0d7b 100644 (file)
@@ -415,6 +415,7 @@ VSTREAM *mail_queue_open(const char *queue_name, const char *queue_id,
      * missing subdirectory.
      */
     if ((fp = vstream_fopen(path, flags, mode)) == 0)
+       if (errno == ENOENT)
        if ((flags & O_CREAT) == O_CREAT && mail_queue_mkdirs(path) == 0)
            fp = vstream_fopen(path, flags, mode);
     return (fp);
index 0b70e37143bcbc8aeff00bc3f2f2201294be9079..d70bbe20cb5b0f6a395ee92b7ff99cc4201448c4 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20010105"
+#define DEF_MAIL_VERSION       "Release-20010119"
 extern char *var_mail_version;
 
 /* LICENSE
index 7c8f4db72d85d3c0070598434956c5c606675929..6e483318590432904934aa4e359f560b878c6f71 100644 (file)
@@ -1,8 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = lmtp.c lmtp_connect.c lmtp_proto.c lmtp_chat.c lmtp_session.c \
-       lmtp_addr.c lmtp_trouble.c lmtp_state.c
+       lmtp_addr.c lmtp_trouble.c lmtp_state.c lmtp_sasl_glue.c \
+       lmtp_sasl_proto.c
 OBJS   = lmtp.o lmtp_connect.o lmtp_proto.o lmtp_chat.o lmtp_session.o \
-       lmtp_addr.o lmtp_trouble.o lmtp_state.o
+       lmtp_addr.o lmtp_trouble.o lmtp_state.o lmtp_sasl_glue.o \
+       lmtp_sasl_proto.o
 HDRS   = lmtp.h
 TESTSRC        = 
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -79,6 +81,7 @@ lmtp.o: ../../include/debug_peer.h
 lmtp.o: ../../include/mail_error.h
 lmtp.o: ../../include/mail_server.h
 lmtp.o: lmtp.h
+lmtp.o: lmtp_sasl.h
 lmtp_addr.o: lmtp_addr.c
 lmtp_addr.o: ../../include/sys_defs.h
 lmtp_addr.o: ../../include/msg.h
@@ -157,7 +160,30 @@ lmtp_proto.o: ../../include/off_cvt.h
 lmtp_proto.o: ../../include/mark_corrupt.h
 lmtp_proto.o: lmtp.h
 lmtp_proto.o: ../../include/argv.h
+lmtp_proto.o: lmtp_sasl.h
 lmtp_proto.o: ../../include/quote_821_local.h
+lmtp_sasl_glue.o: lmtp_sasl_glue.c
+lmtp_sasl_glue.o: ../../include/sys_defs.h
+lmtp_sasl_glue.o: ../../include/msg.h
+lmtp_sasl_glue.o: ../../include/mymalloc.h
+lmtp_sasl_glue.o: ../../include/stringops.h
+lmtp_sasl_glue.o: ../../include/vstring.h
+lmtp_sasl_glue.o: ../../include/vbuf.h
+lmtp_sasl_glue.o: ../../include/split_at.h
+lmtp_sasl_glue.o: ../../include/name_mask.h
+lmtp_sasl_glue.o: ../../include/mail_params.h
+lmtp_sasl_glue.o: ../../include/string_list.h
+lmtp_sasl_glue.o: ../../include/maps.h
+lmtp_sasl_glue.o: ../../include/dict.h
+lmtp_sasl_glue.o: ../../include/vstream.h
+lmtp_sasl_glue.o: ../../include/argv.h
+lmtp_sasl_glue.o: lmtp_sasl.h
+lmtp_sasl_proto.o: lmtp_sasl_proto.c
+lmtp_sasl_proto.o: ../../include/sys_defs.h
+lmtp_sasl_proto.o: ../../include/msg.h
+lmtp_sasl_proto.o: ../../include/mymalloc.h
+lmtp_sasl_proto.o: ../../include/mail_params.h
+lmtp_sasl_proto.o: lmtp_sasl.h
 lmtp_session.o: lmtp_session.c
 lmtp_session.o: ../../include/sys_defs.h
 lmtp_session.o: ../../include/mymalloc.h
@@ -182,6 +208,7 @@ lmtp_state.o: lmtp.h
 lmtp_state.o: ../../include/argv.h
 lmtp_state.o: ../../include/deliver_request.h
 lmtp_state.o: ../../include/recipient_list.h
+lmtp_state.o: lmtp_sasl.h
 lmtp_trouble.o: lmtp_trouble.c
 lmtp_trouble.o: ../../include/sys_defs.h
 lmtp_trouble.o: ../../include/msg.h
index dfd3ec5c3e75abae3edc30d9c727b3400bb6830c..ec0e1c73c04cdd715fc91242e640fb622759af77 100644 (file)
@@ -49,6 +49,7 @@
 /*     RFC 1870 (Message Size Declaration)
 /*     RFC 2033 (LMTP protocol)
 /*     RFC 2197 (Pipelining)
+/*     RFC 2554 (AUTH command)
 /* DIAGNOSTICS
 /*     Problems and transactions are logged to \fBsyslogd\fR(8).
 /*     Corrupted message files are marked so that the queue manager can
 /* .IP \fBlmtp_tcp_port\fR
 /*     The TCP port to be used when connecting to a LMTP server.  Used as
 /*     backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+/* .SH "Authentication controls"
+/* .IP \fBlmtp_enable_sasl_auth\fR
+/*     Enable per-session authentication as per RFC 2554 (SASL).
+/*     By default, Postfix is built without SASL support.
+/* .IP \fBlmtp_sasl_password_maps\fR
+/*     Lookup tables with per-host or domain \fIname\fR:\fIpassword\fR entries.
+/*     No entry for a host means no attempt to authenticate.
+/* .IP \fBlmtp_sasl_security_options\fR
+/*     Zero or more of the following.
+/* .RS
+/* .IP \fBnoplaintext\fR
+/*     Disallow authentication methods that use plaintext passwords.
+/* .IP \fBnoactive\fR
+/*     Disallow authentication methods that are vulnerable to non-dictionary
+/*     active attacks.
+/* .IP \fBnodictionary\fR
+/*     Disallow authentication methods that are vulnerable to passive
+/*     dictionary attack.
+/* .IP \fBnoanonymous\fR
+/*     Disallow anonymous logins.
+/* .RE
 /* .SH "Resource controls"
 /* .ad
 /* .fi
 /* Application-specific. */
 
 #include "lmtp.h"
+#include "lmtp_sasl.h"
 
  /*
   * Tunable parameters. These have compiled-in defaults that can be overruled
@@ -252,6 +275,9 @@ int     var_lmtp_cache_conn;
 int     var_lmtp_skip_quit_resp;
 char   *var_notify_classes;
 char   *var_error_rcpt;
+char   *var_lmtp_sasl_opts;
+char   *var_lmtp_sasl_passwd;
+bool    var_lmtp_sasl_enable;
 
  /*
   * Global variables.
@@ -432,6 +458,10 @@ static void post_init(char *unused_name, char **unused_argv)
 static void pre_init(char *unused_name, char **unused_argv)
 {
     debug_peer_init();
+#ifdef USE_SASL_AUTH
+    if (var_lmtp_sasl_enable)
+       lmtp_sasl_initialize();
+#endif
 }
 
 /* cleanup - close any open connections, etc. */
@@ -446,6 +476,10 @@ static void cleanup(void)
            msg_info("cleanup: just closed down session");
     }
     lmtp_state_free(state);
+#ifdef USE_SASL_AUTH
+    if (var_lmtp_sasl_enable)
+       sasl_done();
+#endif
 }
 
 /* pre_accept - see if tables have changed */
@@ -467,6 +501,8 @@ int     main(int argc, char **argv)
        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_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
+       VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0,
+       VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_lmtp_sasl_opts, 0, 0,
        0,
     };
     static CONFIG_INT_TABLE int_table[] = {
index 0f53c46a716bbd392c7d36d6db89fcd41a4eaf9e..9574b648ac06ea9642719a54e7137a85cf5f7b9f 100644 (file)
@@ -8,6 +8,14 @@
 /* DESCRIPTION
 /* .nf
 
+ /*
+  * SASL library.
+  */
+#ifdef USE_SASL_AUTH
+#include <sasl.h>
+#include <saslutil.h>
+#endif
+
  /*
   * Utility library.
   */
@@ -35,6 +43,15 @@ typedef struct LMTP_STATE {
     int     features;                  /* server features */
     ARGV   *history;                   /* transaction log */
     int     error_mask;                        /* error classes */
+#ifdef USE_SASL_AUTH
+    char   *sasl_mechanism_list;       /* server mechanism list */
+    char   *sasl_username;             /* client username */
+    char   *sasl_passwd;               /* client password */
+    sasl_conn_t *sasl_conn;            /* SASL internal state */
+    VSTRING *sasl_encoded;             /* encoding buffer */
+    VSTRING *sasl_decoded;             /* decoding buffer */
+    sasl_callback_t *sasl_callbacks;   /* stateful callbacks */
+#endif
     int     sndbufsize;                        /* total window size */
     int     sndbuffree;                        /* remaining window */
     int     reuse;                     /* connection being reused */
@@ -44,6 +61,7 @@ typedef struct LMTP_STATE {
 #define LMTP_FEATURE_8BITMIME  (1<<1)
 #define LMTP_FEATURE_PIPELINING        (1<<2)
 #define LMTP_FEATURE_SIZE      (1<<3)
+#define SMTP_FEATURE_AUTH      (1<<5)
 
  /*
   * lmtp.c
index 9fd23f2bf04629fe2e56c880379cc057b4464c05..19b37cc03c4b1698577604fe6a3a362845f13072 100644 (file)
 #include <mail_params.h>
 #include <mail_addr.h>
 #include <post_mail.h>
+#include <mail_error.h>
 
 /* Application-specific. */
 
@@ -172,7 +173,6 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
 {
     LMTP_SESSION *session = state->session;
     static LMTP_RESP rdata;
-    int     more;
     char   *cp;
     int     last_char;
 
@@ -190,17 +190,12 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
     VSTRING_RESET(rdata.buf);
     for (;;) {
        last_char = smtp_get(state->buffer, session->stream, var_line_limit);
-       cp = printable(STR(state->buffer), '?');
+       printable(STR(state->buffer), '?');
        if (last_char != '\n')
            msg_warn("%s: response longer than %d: %.30s...",
-                    session->namaddr, var_line_limit, cp);
+                    session->namaddr, var_line_limit, STR(state->buffer));
        if (msg_verbose)
-           msg_info("< %s: %s", session->namaddr, cp);
-       while (ISDIGIT(*cp))
-           cp++;
-       rdata.code = (cp - STR(state->buffer) == 3 ?
-                     atoi(STR(state->buffer)) : 0);
-       more = (*cp == '-');
+           msg_info("< %s: %s", session->namaddr, STR(state->buffer));
 
        /*
         * Defend against a denial of service attack by limiting the amount
@@ -212,13 +207,23 @@ LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
            vstring_strcat(rdata.buf, STR(state->buffer));
            lmtp_chat_append(state, "In:  ", STR(state->buffer));
        }
-       if (VSTRING_LEN(state->buffer) == 0)    /* XXX remote brain damage */
-           continue;
-       if (!ISDIGIT(STR(state->buffer)[0]))    /* XXX remote brain damage */
-           continue;
-       if (more == 0)
-           break;
+
+       /*
+        * Parse into code and text. Ignore unrecognized garbage. This means
+        * that any character except space (or end of line) will have the
+        * same effect as the '-' line continuation character.
+        */
+       for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
+            /* void */ ;
+       if (cp - STR(state->buffer) == 3) {
+           if (*cp == '-')
+               continue;
+           if (*cp == ' ' || *cp == 0)
+               break;
+       }
+       state->error_mask |= MAIL_ERROR_PROTOCOL;
     }
+    rdata.code = atoi(STR(state->buffer));
     VSTRING_TERMINATE(rdata.buf);
     rdata.str = STR(rdata.buf);
     return (&rdata);
index 93ed07dd0836554e5391009ae5cfe4a7d83d0e4e..9dd965f2bd790cb92b89a8b35b274c98fa617618 100644 (file)
 #include <rec_type.h>
 #include <off_cvt.h>
 #include <mark_corrupt.h>
+#include <quote_821_local.h>
 
 /* Application-specific. */
 
 #include "lmtp.h"
-#include "quote_821_local.h"
+#include "lmtp_sasl.h"
 
  /*
   * Sender and receiver state. A session does not necessarily go through a
@@ -186,14 +187,14 @@ int     lmtp_lhlo(LMTP_STATE *state)
      */
     smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
     if ((except = vstream_setjmp(state->session->stream)) != 0)
-       return (lmtp_stream_except(state, except, "sending LHLO"));
+       return (smtp_stream_except(state, except, "sending LHLO"));
 
     /*
      * Read and parse the server's LMTP greeting banner.
      */
     if (((resp = lmtp_chat_resp(state))->code / 100) != 2)
        return (lmtp_site_fail(state, resp->code,
-                              "%s refused to talk to me: %s",
+                              "host %s refused to talk to me: %s",
                         session->namaddr, translit(resp->str, "\n", " ")));
 
     /*
@@ -202,7 +203,7 @@ int     lmtp_lhlo(LMTP_STATE *state)
     lmtp_chat_cmd(state, "LHLO %s", var_myhostname);
     if ((resp = lmtp_chat_resp(state))->code / 100 != 2)
        return (lmtp_site_fail(state, resp->code,
-                              "%s refused to talk to me: %s",
+                              "host %s refused to talk to me: %s",
                               session->namaddr,
                               translit(resp->str, "\n", " ")));
 
@@ -223,11 +224,20 @@ int     lmtp_lhlo(LMTP_STATE *state)
                state->features |= LMTP_FEATURE_PIPELINING;
            else if (strcasecmp(word, "SIZE") == 0)
                state->features |= LMTP_FEATURE_SIZE;
+#ifdef USE_SASL_AUTH
+           else if (var_lmtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
+               lmtp_sasl_helo_auth(state, words);
+#endif
        }
     }
     if (msg_verbose)
        msg_info("server features: 0x%x", state->features);
 
+#ifdef USE_SASL_AUTH
+    if (var_lmtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH))
+       return (lmtp_sasl_helo_login(state));
+#endif
+
     /*
      * We use LMTP command pipelining if the server said it supported it.
      * Since we use blocking I/O, RFC 2197 says that we should inspect the
@@ -446,7 +456,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                smtp_timeout_setup(state->session->stream,
                                   *xfer_timeouts[recv_state]);
                if ((except = vstream_setjmp(state->session->stream)) != 0)
-                   RETURN(lmtp_stream_except(state, except,
+                   RETURN(smtp_stream_except(state, except,
                                              xfer_states[recv_state]));
                resp = lmtp_chat_resp(state);
 
@@ -463,7 +473,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                case LMTP_STATE_MAIL:
                    if (resp->code / 100 != 2) {
                        lmtp_mesg_fail(state, resp->code,
-                                      "%s said: %s", session->namaddr,
+                                      "host %s said: %s", session->namaddr,
                                       translit(resp->str, "\n", " "));
                        mail_from_rejected = 1;
                    }
@@ -487,7 +497,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                            survivors[nrcpt++] = recv_rcpt;
                        } else {
                            lmtp_rcpt_fail(state, resp->code, rcpt,
-                                          "%s said: %s", session->namaddr,
+                                      "host %s said: %s", session->namaddr,
                                           translit(resp->str, "\n", " "));
                            rcpt->offset = 0;   /* in case deferred */
                        }
@@ -505,7 +515,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                    if (resp->code / 100 != 3) {
                        if (nrcpt > 0)
                            lmtp_mesg_fail(state, resp->code,
-                                          "%s said: %s", session->namaddr,
+                                      "host %s said: %s", session->namaddr,
                                           translit(resp->str, "\n", " "));
                        nrcpt = -1;
                    }
@@ -535,7 +545,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                            }
                        } else {
                            lmtp_rcpt_fail(state, resp->code, rcpt,
-                                          "%s said: %s", session->namaddr,
+                                      "host %s said: %s", session->namaddr,
                                           translit(resp->str, "\n", " "));
                            rcpt->offset = 0;   /* in case deferred */
                        }
@@ -618,7 +628,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
            smtp_timeout_setup(state->session->stream,
                               var_lmtp_data1_tmout);
            if ((except = vstream_setjmp(state->session->stream)) != 0)
-               RETURN(lmtp_stream_except(state, except,
+               RETURN(smtp_stream_except(state, except,
                                          "sending message body"));
 
            if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
diff --git a/postfix/src/lmtp/lmtp_sasl.h b/postfix/src/lmtp/lmtp_sasl.h
new file mode 100644 (file)
index 0000000..1054d68
--- /dev/null
@@ -0,0 +1,39 @@
+/*++
+/* NAME
+/*     lmtp_sasl 3h
+/* SUMMARY
+/*     Postfix SASL interface for LMTP client
+/* SYNOPSIS
+/*     #include "lmtp_sasl.h"
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * SASL protocol functions
+ */
+extern void lmtp_sasl_initialize(void);
+extern void lmtp_sasl_connect(LMTP_STATE *);
+extern int lmtp_sasl_passwd_lookup(LMTP_STATE *);
+extern void lmtp_sasl_start(LMTP_STATE *);
+extern int lmtp_sasl_authenticate(LMTP_STATE *, VSTRING *);
+extern void lmtp_sasl_cleanup(LMTP_STATE *);
+
+extern void lmtp_sasl_helo_auth(LMTP_STATE *, const char *);
+extern int lmtp_sasl_helo_login(LMTP_STATE *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Initial implementation by:
+/*     Till Franke
+/*     SuSE Rhein/Main AG
+/*     65760 Eschborn, Germany
+/*
+/*     Adopted by:
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
diff --git a/postfix/src/lmtp/lmtp_sasl_glue.c b/postfix/src/lmtp/lmtp_sasl_glue.c
new file mode 100644 (file)
index 0000000..ba57156
--- /dev/null
@@ -0,0 +1,512 @@
+/*++
+/* NAME
+/*     lmtp_sasl 3
+/* SUMMARY
+/*     Postfix SASL interface for LMTP client
+/* SYNOPSIS
+/*     #include lmtp_sasl.h
+/*
+/*     void    lmtp_sasl_initialize()
+/*
+/*     void    lmtp_sasl_connect(state)
+/*     LMTP_STATE *state;
+/*
+/*     void    lmtp_sasl_start(state)
+/*     LMTP_STATE *state;
+/*
+/*     int     lmtp_sasl_passwd_lookup(state)
+/*     LMTP_STATE *state;
+/*
+/*     int     lmtp_sasl_authenticate(state, why)
+/*     LMTP_STATE *state;
+/*     VSTRING *why;
+/*
+/*     void    lmtp_sasl_cleanup(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     lmtp_sasl_initialize() initializes the SASL library. This
+/*     routine must be called once at process startup, before any
+/*     chroot operations.
+/*
+/*     lmtp_sasl_connect() performs per-session initialization. This
+/*     routine must be called once at the start of each connection.
+/*
+/*     lmtp_sasl_start() performs per-session initialization. This
+/*     routine must be called once per session before doing any SASL
+/*     authentication.
+/*
+/*     lmtp_sasl_passwd_lookup() looks up the username/password
+/*     for the current SMTP server. The result is zero in case
+/*     of failure.
+/*
+/*     lmtp_sasl_authenticate() implements the SASL authentication
+/*     dialog. The result is < 0 in case of protocol failure, zero in
+/*     case of unsuccessful authentication, > 0 in case of success.
+/*     The why argument is updated with a reason for failure.
+/*     This routine must be called only when lmtp_sasl_passwd_lookup()
+/*     suceeds.
+/*
+/*     lmtp_sasl_cleanup() cleans up. It must be called at the
+/*     end of every SMTP session that uses SASL authentication.
+/*     This routine is a noop for non-SASL sessions.
+/*
+/*     Arguments:
+/* .IP state
+/*     Session context.
+/* .IP mech_list
+/*     String of SASL mechanisms (separated by blanks)
+/* DIAGNOSTICS
+/*     All errors are fatal.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Original author:
+/*     Till Franke
+/*     SuSE Rhein/Main AG
+/*     65760 Eschborn, Germany
+/*
+/*     Adopted by:
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+ /*
+  * Utility library
+  */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <split_at.h>
+#include <name_mask.h>
+
+ /*
+  * Global library
+  */
+#include <mail_params.h>
+#include <string_list.h>
+#include <maps.h>
+
+ /*
+  * Application-specific
+  */
+#include "lmtp.h"
+#include "lmtp_sasl.h"
+
+#ifdef USE_SASL_AUTH
+
+ /*
+  * Authentication security options.
+  */
+static NAME_MASK lmtp_sasl_sec_mask[] = {
+    "noplaintext", SASL_SEC_NOPLAINTEXT,
+    "noactive", SASL_SEC_NOACTIVE,
+    "nodictionary", SASL_SEC_NODICTIONARY,
+    "noanonymous", SASL_SEC_NOANONYMOUS,
+    0,
+};
+
+static int lmtp_sasl_sec_opts;
+
+ /*
+  * Silly little macros.
+  */
+#define STR(x) vstring_str(x)
+
+ /*
+  * Per-host login/password information.
+  */
+static MAPS *lmtp_sasl_passwd_map;
+
+/* lmtp_sasl_log - logging call-back routine */
+
+static int lmtp_sasl_log(void *unused_context, int priority,
+                                const char *message)
+{
+    switch (priority) {
+       case SASL_LOG_ERR:
+       case SASL_LOG_WARNING:
+       msg_warn("%s", message);
+       break;
+    case SASL_LOG_INFO:
+       if (msg_verbose)
+           msg_info("%s", message);
+       break;
+    }
+    return (SASL_OK);
+}
+
+/* lmtp_sasl_get_user - username lookup call-back routine */
+
+static int lmtp_sasl_get_user(void *context, int unused_id, const char **result,
+                                     unsigned *len)
+{
+    char   *myname = "lmtp_sasl_get_user";
+    LMTP_STATE *state = (LMTP_STATE *) context;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, state->sasl_username);
+
+    /*
+     * Sanity check.
+     */
+    if (state->sasl_passwd == 0)
+       msg_panic("%s: no username looked up", myname);
+
+    *result = state->sasl_username;
+    if (len)
+       *len = strlen(state->sasl_username);
+    return (SASL_OK);
+}
+
+/* lmtp_sasl_get_passwd - password lookup call-back routine */
+
+static int lmtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
+                                       int id, sasl_secret_t **psecret)
+{
+    char   *myname = "lmtp_sasl_get_passwd";
+    LMTP_STATE *state = (LMTP_STATE *) context;
+    int     len;
+
+    if (msg_verbose)
+       msg_info("%s: %s", myname, state->sasl_passwd);
+
+    /*
+     * Sanity check.
+     */
+    if (!conn || !psecret || id != SASL_CB_PASS)
+       return (SASL_BADPARAM);
+    if (state->sasl_passwd == 0)
+       msg_panic("%s: no password looked up", myname);
+
+    /*
+     * Convert the password into a counted string.
+     */
+    len = strlen(state->sasl_passwd);
+    if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
+       return (SASL_NOMEM);
+    (*psecret)->len = len;
+    memcpy((*psecret)->data, state->sasl_passwd, len + 1);
+
+    return (SASL_OK);
+}
+
+/* lmtp_sasl_passwd_lookup - password lookup routine */
+
+int     lmtp_sasl_passwd_lookup(LMTP_STATE *state)
+{
+    char   *myname = "lmtp_sasl_passwd_lookup";
+    const char *value;
+    char   *passwd;
+
+    /*
+     * Sanity check.
+     */
+    if (lmtp_sasl_passwd_map == 0)
+       msg_panic("%s: passwd map not initialized", myname);
+
+    /*
+     * Look up the per-server password information. Try the hostname first,
+     * then try the destination.
+     */
+    if ((value = maps_find(lmtp_sasl_passwd_map, state->session->host, 0)) != 0
+       || (value = maps_find(lmtp_sasl_passwd_map, state->request->nexthop, 0)) != 0) {
+       state->sasl_username = mystrdup(value);
+       passwd = split_at(state->sasl_username, ':');
+       state->sasl_passwd = mystrdup(passwd ? passwd : "");
+       if (msg_verbose)
+           msg_info("%s: host `%s' user `%s' pass `%s'",
+                    myname, state->session->host,
+                    state->sasl_username, state->sasl_passwd);
+       return (1);
+    } else {
+       if (msg_verbose)
+           msg_info("%s: host `%s' no auth info found",
+                    myname, state->session->host);
+       return (0);
+    }
+}
+
+/* lmtp_sasl_initialize - per-process initialization (pre jail) */
+
+void    lmtp_sasl_initialize(void)
+{
+
+    /*
+     * Global callbacks. These have no per-session context.
+     */
+    static sasl_callback_t callbacks[] = {
+       {SASL_CB_LOG, &lmtp_sasl_log, 0},
+       {SASL_CB_LIST_END, 0, 0}
+    };
+
+    /*
+     * Sanity check.
+     */
+    if (lmtp_sasl_passwd_map)
+       msg_panic("lmtp_sasl_initialize: repeated call");
+    if (*var_lmtp_sasl_passwd == 0)
+       msg_fatal("specify a password table via the `%s' configuration parameter",
+                 VAR_LMTP_SASL_PASSWD);
+
+    /*
+     * Open the per-host password table and initialize the SASL library. Use
+     * shared locks for reading, just in case someone updates the table.
+     */
+    lmtp_sasl_passwd_map = maps_create("lmtp_sasl_passwd",
+                                      var_lmtp_sasl_passwd, DICT_FLAG_LOCK);
+    if (sasl_client_init(callbacks) != SASL_OK)
+       msg_fatal("SASL library initialization");
+
+    /*
+     * Configuration parameters.
+     */
+    lmtp_sasl_sec_opts = name_mask(VAR_LMTP_SASL_OPTS, lmtp_sasl_sec_mask,
+                                  var_lmtp_sasl_opts);
+}
+
+/* lmtp_sasl_connect - per-session client initialization */
+
+void    lmtp_sasl_connect(LMTP_STATE *state)
+{
+    state->sasl_mechanism_list = 0;
+    state->sasl_username = 0;
+    state->sasl_passwd = 0;
+    state->sasl_conn = 0;
+    state->sasl_encoded = 0;
+    state->sasl_decoded = 0;
+    state->sasl_callbacks = 0;
+}
+
+/* lmtp_sasl_start - per-session SASL initialization */
+
+void    lmtp_sasl_start(LMTP_STATE *state)
+{
+    static sasl_callback_t callbacks[] = {
+       {SASL_CB_USER, &lmtp_sasl_get_user, 0},
+       {SASL_CB_AUTHNAME, &lmtp_sasl_get_user, 0},
+       {SASL_CB_PASS, &lmtp_sasl_get_passwd, 0},
+       {SASL_CB_LIST_END, 0, 0}
+    };
+    sasl_callback_t *cp;
+    sasl_security_properties_t sec_props;
+
+    if (msg_verbose)
+       msg_info("starting new SASL client");
+
+    /*
+     * Per-session initialization. Provide each session with its own callback
+     * context.
+     */
+#define NULL_SECFLAGS          0
+
+    state->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
+    memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
+    for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
+       cp->context = (void *) state;
+    if (sasl_client_new("smtp", state->session->host,
+                       state->sasl_callbacks, NULL_SECFLAGS,
+                       (sasl_conn_t **) &state->sasl_conn) != SASL_OK)
+       msg_fatal("per-session SASL client initialization");
+
+    /*
+     * Per-session security properties. XXX This routine is not sufficiently
+     * documented. What is the purpose of all this?
+     */
+    memset(&sec_props, 0L, sizeof(sec_props));
+    sec_props.min_ssf = 0;
+    sec_props.max_ssf = 1;                     /* don't allow real SASL
+                                                * security layer */
+    sec_props.security_flags = lmtp_sasl_sec_opts;
+    sec_props.maxbufsize = 0;
+    sec_props.property_names = 0;
+    sec_props.property_values = 0;
+    if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
+                    &sec_props) != SASL_OK)
+       msg_fatal("set per-session SASL security properties");
+
+    /*
+     * We use long-lived conversion buffers rather than local variables in
+     * order to avoid memory leaks in case of read/write timeout or I/O
+     * error.
+     */
+    state->sasl_encoded = vstring_alloc(10);
+    state->sasl_decoded = vstring_alloc(10);
+}
+
+/* lmtp_sasl_authenticate - run authentication protocol */
+
+int     lmtp_sasl_authenticate(LMTP_STATE *state, VSTRING *why)
+{
+    char   *myname = "lmtp_sasl_authenticate";
+    unsigned enc_length;
+    unsigned enc_length_out;
+    char   *clientout;
+    unsigned clientoutlen;
+    unsigned serverinlen;
+    LMTP_RESP *resp;
+    const char *mechanism;
+    int     result;
+    char   *line;
+
+#define NO_SASL_SECRET         0
+#define NO_SASL_INTERACTION    0
+#define NO_SASL_LANGLIST       ((const char *) 0)
+#define NO_SASL_OUTLANG                ((const char **) 0)
+
+    if (msg_verbose)
+       msg_info("%s: %s: SASL mechanisms %s",
+              myname, state->session->namaddr, state->sasl_mechanism_list);
+
+    /*
+     * Start the client side authentication protocol.
+     */
+    result = sasl_client_start((sasl_conn_t *) state->sasl_conn,
+                              state->sasl_mechanism_list,
+                              NO_SASL_SECRET, NO_SASL_INTERACTION,
+                              &clientout, &clientoutlen, &mechanism);
+    if (result != SASL_OK && result != SASL_CONTINUE) {
+       vstring_sprintf(why, "cannot SASL authenticate to server %s: %s",
+                       state->session->namaddr,
+                       sasl_errstring(result, NO_SASL_LANGLIST,
+                                      NO_SASL_OUTLANG));
+       return (-1);
+    }
+
+    /*
+     * Send the AUTH command and the optional initial client response.
+     * sasl_encode64() produces four bytes for each complete or incomplete
+     * triple of input bytes. Allocate an extra byte for string termination.
+     */
+#define ENCODE64_LENGTH(n)     ((((n) + 2) / 3) * 4)
+
+    if (clientoutlen > 0) {
+       if (msg_verbose)
+           msg_info("%s: %s: uncoded initial reply: %.*s",
+                    myname, state->session->namaddr,
+                    (int) clientoutlen, clientout);
+       enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
+       VSTRING_SPACE(state->sasl_encoded, enc_length);
+       if (sasl_encode64(clientout, clientoutlen,
+                         STR(state->sasl_encoded), enc_length,
+                         &enc_length_out) != SASL_OK)
+           msg_panic("%s: sasl_encode64 botch", myname);
+       free(clientout);
+       lmtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
+    } else {
+       lmtp_chat_cmd(state, "AUTH %s", mechanism);
+    }
+
+    /*
+     * Step through the authentication protocol until the server tells us
+     * that we are done.
+     */
+    while ((resp = lmtp_chat_resp(state))->code / 100 == 3) {
+
+       /*
+        * Process a server challenge.
+        */
+       line = resp->str;
+       (void) mystrtok(&line, "- \t\n");       /* skip over result code */
+       serverinlen = strlen(line);
+       VSTRING_SPACE(state->sasl_decoded, serverinlen);
+       if (sasl_decode64(line, serverinlen,
+                       STR(state->sasl_decoded), &enc_length) != SASL_OK) {
+           vstring_sprintf(why, "malformed SASL challenge from server %s",
+                           state->session->namaddr);
+           return (-1);
+       }
+       if (msg_verbose)
+           msg_info("%s: %s: decoded challenge: %.*s",
+                    myname, state->session->namaddr,
+                    (int) enc_length, STR(state->sasl_decoded));
+       result = sasl_client_step((sasl_conn_t *) state->sasl_conn,
+                                 STR(state->sasl_decoded), enc_length,
+                           NO_SASL_INTERACTION, &clientout, &clientoutlen);
+       if (result != SASL_OK && result != SASL_CONTINUE)
+           msg_warn("SASL authentication failed to server %s: %s",
+                    state->session->namaddr,
+                    sasl_errstring(result, NO_SASL_LANGLIST,
+                                   NO_SASL_OUTLANG));
+
+       /*
+        * Send a client response.
+        */
+       if (clientoutlen > 0) {
+           if (msg_verbose)
+               msg_info("%s: %s: uncoded client response %.*s",
+                        myname, state->session->namaddr,
+                        (int) clientoutlen, clientout);
+           enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
+           VSTRING_SPACE(state->sasl_encoded, enc_length);
+           if (sasl_encode64(clientout, clientoutlen,
+                             STR(state->sasl_encoded), enc_length,
+                             &enc_length_out) != SASL_OK)
+               msg_panic("%s: sasl_encode64 botch", myname);
+           free(clientout);
+       } else {
+           vstring_strcat(state->sasl_encoded, "");
+       }
+       lmtp_chat_cmd(state, "%s", STR(state->sasl_encoded));
+    }
+
+    /*
+     * We completed the authentication protocol.
+     */
+    if (resp->code / 100 != 2) {
+       vstring_sprintf(why, "SASL authentication failed; server %s said: %s",
+                       state->session->namaddr, resp->str);
+       return (0);
+    }
+    return (1);
+}
+
+/* lmtp_sasl_cleanup - per-session cleanup */
+
+void    lmtp_sasl_cleanup(LMTP_STATE *state)
+{
+    if (state->sasl_username) {
+       myfree(state->sasl_username);
+       state->sasl_username = 0;
+    }
+    if (state->sasl_passwd) {
+       myfree(state->sasl_passwd);
+       state->sasl_passwd = 0;
+    }
+    if (state->sasl_mechanism_list) {
+       myfree(state->sasl_mechanism_list);     /* allocated in lmtp_helo */
+       state->sasl_mechanism_list = 0;
+    }
+    if (state->sasl_conn) {
+       if (msg_verbose)
+           msg_info("disposing SASL state information");
+       sasl_dispose(&state->sasl_conn);
+    }
+    if (state->sasl_callbacks) {
+       myfree((char *) state->sasl_callbacks);
+       state->sasl_callbacks = 0;
+    }
+    if (state->sasl_encoded) {
+       vstring_free(state->sasl_encoded);
+       state->sasl_encoded = 0;
+    }
+    if (state->sasl_decoded) {
+       vstring_free(state->sasl_decoded);
+       state->sasl_decoded = 0;
+    }
+}
+
+#endif
diff --git a/postfix/src/lmtp/lmtp_sasl_proto.c b/postfix/src/lmtp/lmtp_sasl_proto.c
new file mode 100644 (file)
index 0000000..8eaeafd
--- /dev/null
@@ -0,0 +1,120 @@
+/*++
+/* NAME
+/*     lmtp_sasl_proto 3
+/* SUMMARY
+/*     Postfix SASL interface for LMTP client
+/* SYNOPSIS
+/*     #include lmtp_sasl.h
+/*
+/*     void    lmtp_sasl_helo_auth(state, words)
+/*     LMTP_STATE *state;
+/*     const char *words;
+/*
+/*     int     lmtp_sasl_helo_login(state)
+/*     LMTP_STATE *state;
+/* DESCRIPTION
+/*     This module contains random chunks of code that implement
+/*     the SMTP protocol interface for SASL negotiation. The goal
+/*     is to reduce clutter in the main LMTP client source code.
+/*
+/*     lmtp_sasl_helo_auth() processes the AUTH option in the
+/*     SMTP server's EHLO response.
+/*
+/*     lmtp_sasl_helo_login() authenticates the LMTP client to the
+/*     SMTP server, using the authentication mechanism information
+/*     given by the server. The result is a Postfix delivery status
+/*     code in case of trouble.
+/*
+/*     Arguments:
+/* .IP state
+/*     Session context.
+/* .IP words
+/*     List of SASL authentication mechanisms (separated by blanks)
+/* DIAGNOSTICS
+/*     All errors are fatal.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Original author:
+/*     Till Franke
+/*     SuSE Rhein/Main AG
+/*     65760 Eschborn, Germany
+/*
+/*     Adopted by:
+/*     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>
+
+/* Global library. */
+
+#include <mail_params.h>
+
+/* Application-specific. */
+
+#include "lmtp.h"
+#include "lmtp_sasl.h"
+
+#ifdef USE_SASL_AUTH
+
+/* lmtp_sasl_helo_auth - handle AUTH option in EHLO reply */
+
+void    lmtp_sasl_helo_auth(LMTP_STATE *state, const char *words)
+{
+
+    /*
+     * XXX If the server offers a null list of authentication mechanisms,
+     * then pretend that the server doesn't support SASL authentication.
+     */
+    if (state->sasl_mechanism_list) {
+       myfree(state->sasl_mechanism_list);
+       msg_warn("%s offered AUTH option multiple times",
+                state->session->namaddr);
+       state->sasl_mechanism_list = 0;
+       state->features &= ~SMTP_FEATURE_AUTH;
+    }
+    if (strlen(words) > 0) {
+       state->sasl_mechanism_list = mystrdup(words);
+       state->features |= SMTP_FEATURE_AUTH;
+    } else {
+       msg_warn("%s offered null AUTH mechanism list",
+                state->session->namaddr);
+    }
+}
+
+/* lmtp_sasl_helo_login - perform SASL login */
+
+int     lmtp_sasl_helo_login(LMTP_STATE *state)
+{
+    VSTRING *why = vstring_alloc(10);
+    int     ret = 0;
+
+    /*
+     * Skip authentication when no authentication info exists for this
+     * server, so that we talk to each other like strangers. Otherwise, if
+     * authentication information exists, assume that authentication is
+     * required, and assume that an authentication error is recoverable.
+     */
+    if (lmtp_sasl_passwd_lookup(state) != 0) {
+       lmtp_sasl_start(state);
+       if (lmtp_sasl_authenticate(state, why) <= 0)
+           ret = lmtp_site_fail(state, 450, "Authentication failed: %s",
+                                vstring_str(why));
+    }
+    vstring_free(why);
+    return (ret);
+}
+
+#endif
index 7a962660999969cdbeee531dd04c2982267f8975..9f25f814959325bac282429cb7a2434729d3d774 100644 (file)
 
 /* Global library. */
 
-#include <config.h>
+#include <mail_conf.h>
 
 /* Application-specific. */
 
 #include "lmtp.h"
+#include "lmtp_sasl.h"
 
 /* lmtp_state_alloc - initialize */
 
@@ -75,6 +76,9 @@ LMTP_STATE *lmtp_state_alloc(void)
     state->features = 0;
     state->history = 0;
     state->error_mask = 0;
+#ifdef USE_SASL_AUTH
+    lmtp_sasl_connect(state);
+#endif
     state->sndbufsize = 0;
     state->sndbuffree = 0;
     state->reuse = 0;
@@ -88,5 +92,8 @@ void    lmtp_state_free(LMTP_STATE *state)
     vstring_free(state->buffer);
     vstring_free(state->scratch);
     vstring_free(state->scratch2);
+#ifdef USE_SASL_AUTH
+    lmtp_sasl_cleanup(state);
+#endif
     myfree((char *) state);
 }
index 713e4d89b698ad88fcc24f3c0fd98dc0abf69512..38b6185d32a46c382e1159dba2144a60f7b5c464 100644 (file)
@@ -22,7 +22,7 @@
 /*     RECIPIENT *recipient;
 /*     char    *format;
 /*
-/*     int     lmtp_stream_except(state, exception, description)
+/*     int     smtp_stream_except(state, exception, description)
 /*     LMTP_STATE *state;
 /*     int     exception;
 /*     char    *description;
@@ -63,7 +63,7 @@
 /*     recipient limit is reached. The policy is: soft error: defer
 /*     delivery to this recipient; hard error: bounce this recipient.
 /*
-/*     lmtp_stream_except() handles the exceptions generated by
+/*     smtp_stream_except() handles the exceptions generated by
 /*     the smtp_stream(3) module (i.e. timeouts and I/O errors).
 /*     The \fIexception\fR argument specifies the type of problem.
 /*     The \fIdescription\fR argument describes at what stage of
@@ -270,9 +270,9 @@ void    lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
     state->status |= status;
 }
 
-/* lmtp_stream_except - defer domain after I/O problem */
+/* smtp_stream_except - defer domain after I/O problem */
 
-int     lmtp_stream_except(LMTP_STATE *state, int code, char *description)
+int     smtp_stream_except(LMTP_STATE *state, int code, char *description)
 {
     DELIVER_REQUEST *request = state->request;
     LMTP_SESSION *session = state->session;
@@ -285,7 +285,7 @@ int     lmtp_stream_except(LMTP_STATE *state, int code, char *description)
      */
     switch (code) {
     default:
-       msg_panic("lmtp_stream_except: unknown exception %d", code);
+       msg_panic("smtp_stream_except: unknown exception %d", code);
     case SMTP_ERR_EOF:
        vstring_sprintf(why, "lost connection with %s while %s",
                        session->namaddr, description);
diff --git a/postfix/src/nqmgr/.indent.pro b/postfix/src/nqmgr/.indent.pro
deleted file mode 120000 (symlink)
index 5c837ec..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../.indent.pro
\ No newline at end of file
diff --git a/postfix/src/nqmgr/.printfck b/postfix/src/nqmgr/.printfck
deleted file mode 100644 (file)
index 66016ed..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-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         4       0
-post_mail_fprintf      1       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/src/nqmgr/Makefile.in b/postfix/src/nqmgr/Makefile.in
deleted file mode 100644 (file)
index eea19d3..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-SHELL  = /bin/sh
-SRCS   = qmgr.c qmgr_active.c qmgr_transport.c qmgr_queue.c qmgr_entry.c \
-       qmgr_message.c qmgr_deliver.c qmgr_move.c qmgr_rcpt_list.c \
-       qmgr_job.c qmgr_peer.c \
-       qmgr_defer.c qmgr_enable.c qmgr_scan.c qmgr_bounce.c
-OBJS   = qmgr.o qmgr_active.o qmgr_transport.o qmgr_queue.o qmgr_entry.o \
-       qmgr_message.o qmgr_deliver.o qmgr_move.o qmgr_rcpt_list.o \
-       qmgr_job.o qmgr_peer.o \
-       qmgr_defer.o qmgr_enable.o qmgr_scan.o qmgr_bounce.o
-HDRS   = qmgr.h
-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   = qmgr
-INC_DIR        = ../../include
-LIBS   = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
-
-.c.o:; $(CC) $(CFLAGS) -c $*.c
-
-$(PROG):       $(OBJS) $(LIBS)
-       $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
-
-Makefile: Makefile.in
-       (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
-
-test:  $(TESTPROG)
-
-update: ../../libexec/n$(PROG)
-
-../../libexec/n$(PROG): $(PROG)
-       cp $(PROG) ../../libexec/n$(PROG)
-
-printfck: $(OBJS) $(PROG)
-       rm -rf printfck
-       mkdir printfck
-       cp *.h printfck
-       sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
-       set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
-       cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
-
-lint:
-       lint $(DEFS) $(SRCS) $(LINTFIX)
-
-clean:
-       rm -f *.o *core $(PROG) $(TESTPROG) junk 
-       rm -rf printfck
-
-tidy:  clean
-
-depend: $(MAKES)
-       (sed '1,/^# do not edit/!d' Makefile.in; \
-       set -e; for i in [a-z][a-z0-9]*.c; do \
-           $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
-           -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
-       done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
-       @$(EXPORT) make -f Makefile.in Makefile 1>&2
-
-# do not edit below this line - it is generated by 'make depend'
-qmgr.o: qmgr.c
-qmgr.o: ../../include/sys_defs.h
-qmgr.o: ../../include/msg.h
-qmgr.o: ../../include/events.h
-qmgr.o: ../../include/vstream.h
-qmgr.o: ../../include/vbuf.h
-qmgr.o: ../../include/dict.h
-qmgr.o: ../../include/argv.h
-qmgr.o: ../../include/mail_queue.h
-qmgr.o: ../../include/vstring.h
-qmgr.o: ../../include/recipient_list.h
-qmgr.o: ../../include/mail_conf.h
-qmgr.o: ../../include/mail_params.h
-qmgr.o: ../../include/mail_proto.h
-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
-qmgr_active.o: ../../include/msg.h
-qmgr_active.o: ../../include/events.h
-qmgr_active.o: ../../include/mymalloc.h
-qmgr_active.o: ../../include/vstream.h
-qmgr_active.o: ../../include/vbuf.h
-qmgr_active.o: ../../include/mail_params.h
-qmgr_active.o: ../../include/mail_open_ok.h
-qmgr_active.o: ../../include/mail_queue.h
-qmgr_active.o: ../../include/vstring.h
-qmgr_active.o: ../../include/recipient_list.h
-qmgr_active.o: ../../include/bounce.h
-qmgr_active.o: ../../include/defer.h
-qmgr_active.o: ../../include/abounce.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_active.o: ../../include/dict.h
-qmgr_active.o: ../../include/argv.h
-qmgr_bounce.o: qmgr_bounce.c
-qmgr_bounce.o: ../../include/sys_defs.h
-qmgr_bounce.o: ../../include/bounce.h
-qmgr_bounce.o: ../../include/deliver_completed.h
-qmgr_bounce.o: ../../include/vstream.h
-qmgr_bounce.o: ../../include/vbuf.h
-qmgr_bounce.o: qmgr.h
-qmgr_bounce.o: ../../include/scan_dir.h
-qmgr_bounce.o: ../../include/maps.h
-qmgr_bounce.o: ../../include/dict.h
-qmgr_bounce.o: ../../include/argv.h
-qmgr_defer.o: qmgr_defer.c
-qmgr_defer.o: ../../include/sys_defs.h
-qmgr_defer.o: ../../include/msg.h
-qmgr_defer.o: ../../include/vstream.h
-qmgr_defer.o: ../../include/vbuf.h
-qmgr_defer.o: ../../include/defer.h
-qmgr_defer.o: ../../include/bounce.h
-qmgr_defer.o: qmgr.h
-qmgr_defer.o: ../../include/scan_dir.h
-qmgr_defer.o: ../../include/maps.h
-qmgr_defer.o: ../../include/dict.h
-qmgr_defer.o: ../../include/argv.h
-qmgr_deliver.o: qmgr_deliver.c
-qmgr_deliver.o: ../../include/sys_defs.h
-qmgr_deliver.o: ../../include/msg.h
-qmgr_deliver.o: ../../include/vstring.h
-qmgr_deliver.o: ../../include/vbuf.h
-qmgr_deliver.o: ../../include/vstream.h
-qmgr_deliver.o: ../../include/vstring_vstream.h
-qmgr_deliver.o: ../../include/events.h
-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: ../../include/deliver_request.h
-qmgr_deliver.o: qmgr.h
-qmgr_deliver.o: ../../include/scan_dir.h
-qmgr_deliver.o: ../../include/maps.h
-qmgr_deliver.o: ../../include/dict.h
-qmgr_deliver.o: ../../include/argv.h
-qmgr_enable.o: qmgr_enable.c
-qmgr_enable.o: ../../include/sys_defs.h
-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_enable.o: ../../include/dict.h
-qmgr_enable.o: ../../include/argv.h
-qmgr_entry.o: qmgr_entry.c
-qmgr_entry.o: ../../include/sys_defs.h
-qmgr_entry.o: ../../include/msg.h
-qmgr_entry.o: ../../include/mymalloc.h
-qmgr_entry.o: ../../include/events.h
-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_entry.o: ../../include/dict.h
-qmgr_entry.o: ../../include/argv.h
-qmgr_job.o: qmgr_job.c
-qmgr_job.o: ../../include/sys_defs.h
-qmgr_job.o: ../../include/msg.h
-qmgr_job.o: ../../include/events.h
-qmgr_job.o: ../../include/htable.h
-qmgr_job.o: ../../include/mymalloc.h
-qmgr_job.o: qmgr.h
-qmgr_job.o: ../../include/vstream.h
-qmgr_job.o: ../../include/vbuf.h
-qmgr_job.o: ../../include/scan_dir.h
-qmgr_job.o: ../../include/maps.h
-qmgr_job.o: ../../include/dict.h
-qmgr_job.o: ../../include/argv.h
-qmgr_message.o: qmgr_message.c
-qmgr_message.o: ../../include/sys_defs.h
-qmgr_message.o: ../../include/msg.h
-qmgr_message.o: ../../include/events.h
-qmgr_message.o: ../../include/mymalloc.h
-qmgr_message.o: ../../include/vstring.h
-qmgr_message.o: ../../include/vbuf.h
-qmgr_message.o: ../../include/vstream.h
-qmgr_message.o: ../../include/split_at.h
-qmgr_message.o: ../../include/valid_hostname.h
-qmgr_message.o: ../../include/argv.h
-qmgr_message.o: ../../include/stringops.h
-qmgr_message.o: ../../include/myflock.h
-qmgr_message.o: ../../include/dict.h
-qmgr_message.o: ../../include/mail_queue.h
-qmgr_message.o: ../../include/mail_params.h
-qmgr_message.o: ../../include/canon_addr.h
-qmgr_message.o: ../../include/record.h
-qmgr_message.o: ../../include/rec_type.h
-qmgr_message.o: ../../include/sent.h
-qmgr_message.o: ../../include/deliver_completed.h
-qmgr_message.o: ../../include/mail_addr_find.h
-qmgr_message.o: ../../include/maps.h
-qmgr_message.o: ../../include/opened.h
-qmgr_message.o: ../../include/resolve_local.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
-qmgr_move.o: ../../include/scan_dir.h
-qmgr_move.o: ../../include/recipient_list.h
-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_move.o: ../../include/dict.h
-qmgr_move.o: ../../include/argv.h
-qmgr_peer.o: qmgr_peer.c
-qmgr_peer.o: ../../include/sys_defs.h
-qmgr_peer.o: ../../include/msg.h
-qmgr_peer.o: ../../include/htable.h
-qmgr_peer.o: ../../include/mymalloc.h
-qmgr_peer.o: qmgr.h
-qmgr_peer.o: ../../include/vstream.h
-qmgr_peer.o: ../../include/vbuf.h
-qmgr_peer.o: ../../include/scan_dir.h
-qmgr_peer.o: ../../include/maps.h
-qmgr_peer.o: ../../include/dict.h
-qmgr_peer.o: ../../include/argv.h
-qmgr_queue.o: qmgr_queue.c
-qmgr_queue.o: ../../include/sys_defs.h
-qmgr_queue.o: ../../include/msg.h
-qmgr_queue.o: ../../include/mymalloc.h
-qmgr_queue.o: ../../include/events.h
-qmgr_queue.o: ../../include/htable.h
-qmgr_queue.o: ../../include/mail_params.h
-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_queue.o: ../../include/dict.h
-qmgr_queue.o: ../../include/argv.h
-qmgr_rcpt_list.o: qmgr_rcpt_list.c
-qmgr_rcpt_list.o: ../../include/sys_defs.h
-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_rcpt_list.o: ../../include/dict.h
-qmgr_rcpt_list.o: ../../include/argv.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
-qmgr_scan.o: ../../include/maps.h
-qmgr_scan.o: ../../include/dict.h
-qmgr_scan.o: ../../include/argv.h
-qmgr_transport.o: qmgr_transport.c
-qmgr_transport.o: ../../include/sys_defs.h
-qmgr_transport.o: ../../include/msg.h
-qmgr_transport.o: ../../include/htable.h
-qmgr_transport.o: ../../include/events.h
-qmgr_transport.o: ../../include/mymalloc.h
-qmgr_transport.o: ../../include/vstream.h
-qmgr_transport.o: ../../include/vbuf.h
-qmgr_transport.o: ../../include/iostuff.h
-qmgr_transport.o: ../../include/mail_proto.h
-qmgr_transport.o: ../../include/recipient_list.h
-qmgr_transport.o: ../../include/mail_conf.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
-qmgr_transport.o: ../../include/dict.h
-qmgr_transport.o: ../../include/argv.h
diff --git a/postfix/src/nqmgr/qmgr.c b/postfix/src/nqmgr/qmgr.c
deleted file mode 100644 (file)
index c7cbd62..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/*++
-/* NAME
-/*     qmgr 8
-/* SUMMARY
-/*     Postfix queue manager
-/* SYNOPSIS
-/*     \fBqmgr\fR [generic Postfix daemon options]
-/* DESCRIPTION
-/*     The \fBqmgr\fR daemon awaits the arrival of incoming mail
-/*     and arranges for its delivery via Postfix delivery processes.
-/*     The actual mail routing strategy is delegated to the
-/*     \fBtrivial-rewrite\fR(8) daemon.
-/*     This program expects to be run from the \fBmaster\fR(8) process
-/*     manager.
-/*
-/*     Mail addressed to the local \fBdouble-bounce\fR address is silently
-/*     discarded.  This stops potential loops caused by undeliverable
-/*     bounce notifications.
-/*
-/*     Mail addressed to a user listed in the optional \fBrelocated\fR
-/*     database is bounced with a "user has moved to \fInew_location\fR"
-/*     message. See \fBrelocated\fR(5) for a precise description.
-/* MAIL QUEUES
-/* .ad
-/* .fi
-/*     The \fBqmgr\fR daemon maintains the following queues:
-/* .IP \fBincoming\fR
-/*     Inbound mail from the network, or mail picked up by the
-/*     local \fBpickup\fR agent from the \fBmaildrop\fR directory.
-/* .IP \fBactive\fR
-/*     Messages that the queue manager has opened for delivery. Only
-/*     a limited number of messages is allowed to enter the \fBactive\fR
-/*     queue (leaky bucket strategy, for a fixed delivery rate).
-/* .IP \fBdeferred\fR
-/*     Mail that could not be delivered upon the first attempt. The queue
-/*     manager implements exponential backoff by doubling the time between
-/*     delivery attempts.
-/* .IP \fBcorrupt\fR
-/*     Unreadable or damaged queue files are moved here for inspection.
-/* DELIVERY STATUS REPORTS
-/* .ad
-/* .fi
-/*     The \fBqmgr\fR daemon keeps an eye on per-message delivery status
-/*     reports in the following directories. Each status report file has
-/*     the same name as the corresponding message file:
-/* .IP \fBbounce\fR
-/*     Per-recipient status information about why mail is bounced.
-/*     These files are maintained by the \fBbounce\fR(8) daemon.
-/* .IP \fBdefer\fR
-/*     Per-recipient status information about why mail is delayed.
-/*     These files are maintained by the \fBdefer\fR(8) daemon.
-/* .PP
-/*     The \fBqmgr\fR daemon is responsible for asking the
-/*     \fBbounce\fR(8) or \fBdefer\fR(8) daemons to send non-delivery
-/*     reports.
-/* STRATEGIES
-/* .ad
-/* .fi
-/*     The queue manager implements a variety of strategies for
-/*     either opening queue files (input) or for message delivery (output).
-/* .IP "\fBleaky bucket\fR"
-/*     This strategy limits the number of messages in the \fBactive\fR queue
-/*     and prevents the queue manager from running out of memory under
-/*     heavy load.
-/* .IP \fBfairness\fR
-/*     When the \fBactive\fR queue has room, the queue manager takes one
-/*     message from the \fBincoming\fR queue and one from the \fBdeferred\fR
-/*     queue. This prevents a large mail backlog from blocking the delivery
-/*     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
-/*     The queue manager sorts delivery requests by destination.
-/*     Round-robin selection prevents one destination from dominating
-/*     deliveries to other destinations.
-/* .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
-/*     attempt.
-/* .IP "\fBdestination status cache\fR"
-/*     The queue manager avoids unnecessary delivery attempts by
-/*     maintaining a short-term, in-memory list of unreachable destinations.
-/* .IP "\fBpreemptive message scheduling\fR"
-/*     The queue manager attempts to minimize the average per-recipient delay
-/*     while still preserving the correct per-message delays, using
-/*     a sophisticated preemptive message scheduling.
-/* TRIGGERS
-/* .ad
-/* .fi
-/*     On an idle system, the queue manager waits for the arrival of
-/*     trigger events, or it waits for a timer to go off. A trigger
-/*     is a one-byte message.
-/*     Depending on the message received, the queue manager performs
-/*     one of the following actions (the message is followed by the
-/*     symbolic constant used internally by the software):
-/* .IP "\fBD (QMGR_REQ_SCAN_DEFERRED)\fR"
-/*     Start a deferred queue scan.  If a deferred queue scan is already
-/*     in progress, that scan will be restarted as soon as it finishes.
-/* .IP "\fBI (QMGR_REQ_SCAN_INCOMING)\fR"
-/*     Start an incoming queue scan. If an incoming queue scan is already
-/*     in progress, that scan will be restarted as soon as it finishes.
-/* .IP "\fBA (QMGR_REQ_SCAN_ALL)\fR"
-/*     Ignore deferred queue file time stamps. The request affects
-/*     the next deferred queue scan.
-/* .IP "\fBF (QMGR_REQ_FLUSH_DEAD)\fR"
-/*     Purge all information about dead transports and destinations.
-/* .IP "\fBW (TRIGGER_REQ_WAKEUP)\fR"
-/*     Wakeup call, This is used by the master server to instantiate
-/*     servers that should not go away forever. The action is to start
-/*     an incoming queue scan.
-/* .PP
-/*     The \fBqmgr\fR daemon reads an entire buffer worth of triggers.
-/*     Multiple identical trigger requests are collapsed into one, and
-/*     trigger requests are sorted so that \fBA\fR and \fBF\fR precede
-/*     \fBD\fR and \fBI\fR. Thus, in order to force a deferred queue run,
-/*     one would request \fBA F D\fR; in order to notify the queue manager
-/*     of the arrival of new mail one would request \fBI\fR.
-/* STANDARDS
-/* .ad
-/* .fi
-/*     None. The \fBqmgr\fR daemon does not interact with the outside world.
-/* SECURITY
-/* .ad
-/* .fi
-/*     The \fBqmgr\fR daemon is not security sensitive. It reads
-/*     single-character messages from untrusted local users, and thus may
-/*     be susceptible to denial of service attacks. The \fBqmgr\fR daemon
-/*     does not talk to the outside world, and it can be run at fixed low
-/*     privilege in a chrooted environment.
-/* DIAGNOSTICS
-/*     Problems and transactions are logged to the syslog daemon.
-/*     Corrupted message files are saved to the \fBcorrupt\fR queue
-/*     for further inspection.
-/*
-/*     Depending on the setting of the \fBnotify_classes\fR parameter,
-/*     the postmaster is notified of bounces and of other trouble.
-/* BUGS
-/*     A single queue manager process has to compete for disk access with
-/*     multiple front-end processes such as \fBsmtpd\fR. A sudden burst of
-/*     inbound mail can negatively impact outbound delivery rates.
-/* CONFIGURATION PARAMETERS
-/* .ad
-/* .fi
-/*      The following \fBmain.cf\fR parameters are especially relevant to
-/*      this program. See the Postfix \fBmain.cf\fR file for syntax details
-/*      and for default values. Use the \fBpostfix reload\fR command after
-/*      a configuration change.
-/* .SH Miscellaneous
-/* .ad
-/* .fi
-/* .IP \fBallow_min_user\fR
-/*     Do not bounce recipient addresses that begin with '-'.
-/* .IP \fBrelocated_maps\fR
-/*     Tables with contact information for users, hosts or domains
-/*     that no longer exist. See \fBrelocated\fR(5).
-/* .IP \fBqueue_directory\fR
-/*     Top-level directory of the Postfix queue.
-/* .SH "Active queue controls"
-/* .ad
-/* .fi
-/*     In the text below, \fItransport\fR is the first field in a
-/*     \fBmaster.cf\fR entry.
-/* .IP \fBqmgr_message_active_limit\fR
-/*     Limit the number of messages in the active queue.
-/* .IP \fBqmgr_message_recipient_limit\fR
-/*     Limit the number of in-memory recipients.
-/* .sp
-/*     This parameter also limits the size of the short-term, in-memory
-/*     destination cache.
-/* .IP \fBqmgr_message_recipient_minimum\fR
-/*     Per message minimum of in-memory recipients.
-/* .IP \fBdefault_recipient_limit\fR
-/*     Default limit on the number of in-memory recipients per transport.
-/* .IP \fItransport\fB_recipient_limit\fR
-/*     Limit on the number of in-memory recipients, for the named
-/*     message \fItransport\fR.
-/* .IP \fBdefault_extra_recipient_limit\fR
-/*     Default limit on the total number of per transport in-memory
-/*     recipients that the preempting messages can have.
-/* .IP \fItransport\fB_extra_recipient_limit\fR
-/*     Limit on the number of in-memory recipients which all preempting
-/*     messages delivered by the transport \fItransport\fR can have.
-/* .SH "Timing controls"
-/* .ad
-/* .fi
-/* .IP \fBmin_backoff\fR
-/*     Minimal time in seconds between delivery attempts
-/*     of a deferred message.
-/* .sp
-/*     This parameter also limits the time an unreachable destination
-/*     is kept in the short-term, in-memory destination status cache.
-/* .IP \fBmax_backoff\fR
-/*     Maximal time in seconds between delivery attempts
-/*     of a deferred message.
-/* .IP \fBmaximal_queue_lifetime\fR
-/*     Maximal time in days a message is queued
-/*     before it is sent back as undeliverable.
-/* .IP \fBqueue_run_delay\fR
-/*     Time in seconds between deferred queue scans. Queue scans do
-/*     not overlap.
-/* .IP \fBtransport_retry_time\fR
-/*     Time in seconds between attempts to contact a broken
-/*     delivery transport.
-/* .SH "Concurrency controls"
-/* .ad
-/* .fi
-/* .IP \fBinitial_destination_concurrency\fR
-/*     Initial per-destination concurrency level for parallel delivery
-/*     to the same destination.
-/* .IP \fBdefault_destination_concurrency_limit\fR
-/*     Default limit on the number of parallel deliveries to the same
-/*     destination.
-/* .IP \fItransport\fB_destination_concurrency_limit\fR
-/*     Limit on the number of parallel deliveries to the same destination,
-/*     for delivery via the named message \fItransport\fR.
-/* .SH "Recipient controls"
-/* .ad
-/* .fi
-/* .IP \fBdefault_destination_recipient_limit\fR
-/*     Default limit on the number of recipients per message transfer.
-/* .IP \fItransport\fB_destination_recipient_limit\fR
-/*     Limit on the number of recipients per message transfer, for the
-/*     named message \fItransport\fR.
-/* .SH "Message scheduling"
-/* .ad
-/* .fi
-/* .IP "\fItransport\fB_delivery_slot_cost\fR (valid range: 0,2,3...)
-/*     This parameter basically controls how often a message
-/*     delivered by \fItransport\fR can be preempted by another
-/*     message.
-/*     An internal per-message/transport counter is incremented by one
-/*     for each \fItransport\fB_delivery_slot_cost\fR
-/*     deliveries handled by \fItransport\fR. This counter represents
-/*     the number of "available delivery slots" for use by other messages.
-/*     Current message can be preempted by another message when that
-/*     other message can be delivered using less \fItransport\fR agents
-/*     than the value of the "available delivery slots" counter.
-/* .sp
-/*     Value equal to 0 disables the message preemption for \fItransport\fR.
-/* .IP \fItransport\fB_minimum_delivery_slots\fR
-/*     Message preemption is not attempted at all whenever a message
-/*     that can't ever accumulate at least \fItransport\fB_minimum_delivery_slots\fR
-/*     available delivery slots is being delivered by \fItransport\fR.
-/* .IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)"
-/* .IP \fItransport\fB_delivery_slot_loan\fR
-/*     These parameters speed up the moment when a message preemption can happen.
-/*     Instead of waiting until the full amount of delivery slots
-/*     required is available, the preemption can happen when
-/*     \fItransport\fB_delivery_slot_discount\fR percent of the required
-/*     amount plus \fItransport\fB_delivery_slot_loan\fR still remains to
-/*     be accumulated. Note that the full amount will still have to be
-/*     accumulated before another preemption can take place later.
-/* .IP \fBdefault_delivery_slot_cost\fR
-/* .IP \fBdefault_minimum_delivery_slots\fR
-/* .IP \fBdefault_delivery_slot_discount\fR
-/* .IP \fBdefault_delivery_slot_loan\fR
-/*     Default values for the transport specific parameters described above.
-/* SEE ALSO
-/*     master(8), process manager
-/*     relocated(5), format of the "user has moved" table
-/*     syslogd(8) system logging
-/*     trivial-rewrite(8), address routing
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <events.h>
-#include <vstream.h>
-#include <dict.h>
-
-/* Global library. */
-
-#include <mail_queue.h>
-#include <recipient_list.h>
-#include <mail_conf.h>
-#include <mail_params.h>
-#include <mail_proto.h>                        /* QMGR_SCAN constants */
-
-/* Master process interface */
-
-#include <master_proto.h>
-#include <mail_server.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
- /*
-  * Tunables.
-  */
-int     var_queue_run_delay;
-int     var_min_backoff_time;
-int     var_max_backoff_time;
-int     var_max_queue_time;
-int     var_qmgr_active_limit;
-int     var_qmgr_rcpt_limit;
-int     var_qmgr_msg_rcpt_limit;
-int     var_xport_rcpt_limit;
-int     var_stack_rcpt_limit;
-int     var_delivery_slot_cost;
-int     var_delivery_slot_loan;
-int     var_delivery_slot_discount;
-int     var_min_delivery_slots;
-int     var_init_dest_concurrency;
-int     var_transport_retry_time;
-int     var_dest_con_limit;
-int     var_dest_rcpt_limit;
-char   *var_relocated_maps;
-char   *var_virtual_maps;
-char   *var_defer_xports;
-bool    var_allow_min_user;
-
-static QMGR_SCAN *qmgr_incoming;
-static QMGR_SCAN *qmgr_deferred;
-
-MAPS   *qmgr_relocated;
-MAPS   *qmgr_virtual;
-
-/* qmgr_deferred_run_event - queue manager heartbeat */
-
-static void qmgr_deferred_run_event(int unused_event, char *dummy)
-{
-
-    /*
-     * This routine runs when it is time for another deferred queue scan.
-     * Make sure this routine gets called again in the future.
-     */
-    qmgr_scan_request(qmgr_deferred, QMGR_SCAN_START);
-    event_request_timer(qmgr_deferred_run_event, dummy, var_queue_run_delay);
-}
-
-/* qmgr_trigger_event - respond to external trigger(s) */
-
-static void qmgr_trigger_event(char *buf, int len,
-                                      char *unused_service, char **argv)
-{
-    int     incoming_flag = 0;
-    int     deferred_flag = 0;
-    int     i;
-
-    /*
-     * Sanity check. This service takes no command-line arguments.
-     */
-    if (argv[0])
-       msg_fatal("unexpected command-line argument: %s", argv[0]);
-
-    /*
-     * Collapse identical requests that have arrived since we looked last
-     * time. There is no client feedback so there is no need to process each
-     * request in order. And as long as we don't have conflicting requests we
-     * are free to sort them into the most suitable order.
-     */
-    for (i = 0; i < len; i++) {
-       if (msg_verbose)
-           msg_info("request: %d (%c)",
-                    buf[i], ISALNUM(buf[i]) ? buf[i] : '?');
-       switch (buf[i]) {
-       case TRIGGER_REQ_WAKEUP:
-       case QMGR_REQ_SCAN_INCOMING:
-           incoming_flag |= QMGR_SCAN_START;
-           break;
-       case QMGR_REQ_SCAN_DEFERRED:
-           deferred_flag |= QMGR_SCAN_START;
-           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)
-               msg_info("request ignored");
-           break;
-       }
-    }
-
-    /*
-     * Process each request type at most once. Modifiers take effect upon the
-     * next queue run. If no queue run is in progress, and a queue scan is
-     * requested, the request takes effect immediately.
-     */
-    if (incoming_flag != 0)
-       qmgr_scan_request(qmgr_incoming, incoming_flag);
-    if (deferred_flag != 0)
-       qmgr_scan_request(qmgr_deferred, deferred_flag);
-}
-
-/* qmgr_loop - queue manager main loop */
-
-static int qmgr_loop(char *unused_name, char **unused_argv)
-{
-    char   *in_path = 0;
-    char   *df_path = 0;
-
-    /*
-     * This routine runs as part of the event handling loop, after the event
-     * manager has delivered a timer or I/O event (including the completion
-     * of a connection to a delivery process), or after it has waited for a
-     * specified amount of time. The result value of qmgr_loop() specifies
-     * how long the event manager should wait for the next event.
-     */
-#define DONT_WAIT      0
-#define WAIT_FOR_EVENT (-1)
-
-    /*
-     * Attempt to drain the active queue by allocating a suitable delivery
-     * process and by delivering mail via it. Delivery process allocation and
-     * mail delivery are asynchronous.
-     */
-    qmgr_active_drain();
-
-    /*
-     * Let some new blood into the active queue when the queue size is
-     * smaller than some configurable limit. When the system is under heavy
-     * load, favor new mail over old mail.
-     */
-    if (qmgr_message_count < var_qmgr_active_limit)
-       if ((in_path = qmgr_scan_next(qmgr_incoming)) != 0)
-           qmgr_active_feed(qmgr_incoming, in_path);
-    if (qmgr_message_count < var_qmgr_active_limit)
-       if ((df_path = qmgr_scan_next(qmgr_deferred)) != 0)
-           qmgr_active_feed(qmgr_deferred, df_path);
-    if (in_path || df_path)
-       return (DONT_WAIT);
-    return (WAIT_FOR_EVENT);
-}
-
-/* pre_accept - see if tables have changed */
-
-static void pre_accept(char *unused_name, char **unused_argv)
-{
-    if (dict_changed()) {
-       msg_info("table has changed -- exiting");
-       exit(0);
-    }
-}
-
-/* qmgr_pre_init - pre-jail initialization */
-
-static void qmgr_pre_init(char *unused_name, char **unused_argv)
-{
-    if (*var_relocated_maps)
-       qmgr_relocated = maps_create("relocated", var_relocated_maps,
-                                    DICT_FLAG_LOCK);
-    if (*var_virtual_maps)
-       qmgr_virtual = maps_create("virtual", var_virtual_maps,
-                                  DICT_FLAG_LOCK);
-}
-
-/* qmgr_post_init - post-jail initialization */
-
-static void qmgr_post_init(char *unused_name, char **unused_argv)
-{
-
-    /*
-     * 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 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_INCOMING, event_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(0, (char *) 0);
-}
-
-/* main - the main program */
-
-int     main(int argc, char **argv)
-{
-    static CONFIG_STR_TABLE str_table[] = {
-       VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
-       VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0,
-       VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0,
-       0,
-    };
-    static CONFIG_TIME_TABLE time_table[] = {
-       VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0,
-       VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0,
-       VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0,
-       VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000,
-       VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0,
-       0,
-    };
-    static CONFIG_INT_TABLE int_table[] = {
-       VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0,
-       VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 1, 0,
-       VAR_QMGR_MSG_RCPT_LIMIT, DEF_QMGR_MSG_RCPT_LIMIT, &var_qmgr_msg_rcpt_limit, 1, 0,
-       VAR_XPORT_RCPT_LIMIT, DEF_XPORT_RCPT_LIMIT, &var_xport_rcpt_limit, 0, 0,
-       VAR_STACK_RCPT_LIMIT, DEF_STACK_RCPT_LIMIT, &var_stack_rcpt_limit, 0, 0,
-       VAR_DELIVERY_SLOT_COST, DEF_DELIVERY_SLOT_COST, &var_delivery_slot_cost, 0, 0,
-       VAR_DELIVERY_SLOT_LOAN, DEF_DELIVERY_SLOT_LOAN, &var_delivery_slot_loan, 0, 0,
-       VAR_DELIVERY_SLOT_DISCOUNT, DEF_DELIVERY_SLOT_DISCOUNT, &var_delivery_slot_discount, 0, 100,
-       VAR_MIN_DELIVERY_SLOTS, DEF_MIN_DELIVERY_SLOTS, &var_min_delivery_slots, 0, 0,
-       VAR_INIT_DEST_CON, DEF_INIT_DEST_CON, &var_init_dest_concurrency, 1, 0,
-       VAR_DEST_CON_LIMIT, DEF_DEST_CON_LIMIT, &var_dest_con_limit, 0, 0,
-       VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0,
-       0,
-    };
-    static CONFIG_BOOL_TABLE bool_table[] = {
-       VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
-       0,
-    };
-
-    /*
-     * Use the trigger service skeleton, because no-one else should be
-     * monitoring our service port while this process runs, and because we do
-     * not talk back to the client.
-     */
-    trigger_server_main(argc, argv, qmgr_trigger_event,
-                       MAIL_SERVER_INT_TABLE, int_table,
-                       MAIL_SERVER_STR_TABLE, str_table,
-                       MAIL_SERVER_BOOL_TABLE, bool_table,
-                       MAIL_SERVER_TIME_TABLE, time_table,
-                       MAIL_SERVER_PRE_INIT, qmgr_pre_init,
-                       MAIL_SERVER_POST_INIT, qmgr_post_init,
-                       MAIL_SERVER_LOOP, qmgr_loop,
-                       MAIL_SERVER_PRE_ACCEPT, pre_accept,
-                       0);
-}
diff --git a/postfix/src/nqmgr/qmgr.h b/postfix/src/nqmgr/qmgr.h
deleted file mode 100644 (file)
index 2da9dea..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*++
-/* NAME
-/*     qmgr 3h
-/* SUMMARY
-/*     queue manager data structures
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/* DESCRIPTION
-/* .nf
-
- /*
-  * Utility library.
-  */
-#include <vstream.h>
-#include <scan_dir.h>
-
- /*
-  * Global library.
-  */
-#include <maps.h>
-
- /*
-  * The queue manager is built around lots of mutually-referring structures.
-  * These typedefs save some typing.
-  */
-typedef struct QMGR_TRANSPORT QMGR_TRANSPORT;
-typedef struct QMGR_QUEUE QMGR_QUEUE;
-typedef struct QMGR_ENTRY QMGR_ENTRY;
-typedef struct QMGR_MESSAGE QMGR_MESSAGE;
-typedef struct QMGR_JOB QMGR_JOB;
-typedef struct QMGR_PEER QMGR_PEER;
-typedef struct QMGR_TRANSPORT_LIST QMGR_TRANSPORT_LIST;
-typedef struct QMGR_QUEUE_LIST QMGR_QUEUE_LIST;
-typedef struct QMGR_ENTRY_LIST QMGR_ENTRY_LIST;
-typedef struct QMGR_JOB_LIST QMGR_JOB_LIST;
-typedef struct QMGR_PEER_LIST QMGR_PEER_LIST;
-typedef struct QMGR_RCPT QMGR_RCPT;
-typedef struct QMGR_RCPT_LIST QMGR_RCPT_LIST;
-typedef struct QMGR_SCAN QMGR_SCAN;
-
- /*
-  * Hairy macros to update doubly-linked lists.
-  */
-#define QMGR_LIST_ROTATE(head, object, peers) { \
-    head.next->peers.prev = head.prev; \
-    head.prev->peers.next = head.next; \
-    head.next = object->peers.next; \
-    head.next->peers.prev = 0; \
-    head.prev = object; \
-    object->peers.next = 0; \
-}
-
-#define QMGR_LIST_UNLINK(head, type, object, peers) { \
-    type   next = object->peers.next; \
-    type   prev = object->peers.prev; \
-    if (prev) prev->peers.next = next; \
-    else head.next = next; \
-    if (next) next->peers.prev = prev; \
-    else head.prev = prev; \
-    object->peers.next = object->peers.prev = 0; \
-}
-
-#define QMGR_LIST_PREPEND(head, object, peers) { \
-    object->peers.next = head.next; \
-    object->peers.prev = 0; \
-    if (head.next) { \
-       head.next->peers.prev = object; \
-    } else { \
-       head.prev = object; \
-    } \
-    head.next = object; \
-}
-
-#define QMGR_LIST_APPEND(head, object, peers) { \
-    object->peers.prev = head.prev; \
-    object->peers.next = 0; \
-    if (head.prev) { \
-       head.prev->peers.next = object; \
-    } else { \
-       head.next = object; \
-    } \
-    head.prev = object; \
-}
-
-#define QMGR_LIST_INIT(head) { \
-    head.prev = 0; \
-    head.next = 0; \
-}
-
- /*
-  * Transports are looked up by name (when we have resolved a message), or
-  * round-robin wise (when we want to distribute resources fairly).
-  */
-struct QMGR_TRANSPORT_LIST {
-    QMGR_TRANSPORT *next;
-    QMGR_TRANSPORT *prev;
-};
-
-extern struct HTABLE *qmgr_transport_byname;   /* transport by name */
-extern QMGR_TRANSPORT_LIST qmgr_transport_list;        /* transports, round robin */
-
- /*
-  * Each transport (local, smtp-out, bounce) can have one queue per next hop
-  * name. Queues are looked up by next hop name (when we have resolved a
-  * message destination), or round-robin wise (when we want to deliver
-  * messages fairly).
-  */
-struct QMGR_QUEUE_LIST {
-    QMGR_QUEUE *next;
-    QMGR_QUEUE *prev;
-};
-
-struct QMGR_JOB_LIST {
-    QMGR_JOB *next;
-    QMGR_JOB *prev;
-};
-
-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 */
-    int     rcpt_per_stack;            /* extra slots reserved for jobs on
-                                        * the job stack */
-    int     rcpt_unused;               /* available in-core recipient slots */
-    int     slot_cost;                 /* cost of new preemption slot (# of
-                                        * selected entries) */
-    int     slot_loan;                 /* preemption boost offset and */
-    int     slot_loan_factor;          /* factor, see qmgr_job_preempt() */
-    int     min_slots;                 /* when preemption can take effect at
-                                        * all */
-    struct HTABLE *queue_byname;       /* queues indexed by domain */
-    QMGR_QUEUE_LIST queue_list;                /* queues, round robin order */
-    struct HTABLE *job_byname;         /* jobs indexed by queue id */
-    QMGR_JOB_LIST job_list;            /* list of message jobs (1 per
-                                        * message) */
-    QMGR_JOB_LIST job_stack;           /* job stack for tracking preemption */
-    QMGR_JOB *job_next_unread;         /* next job with unread recipients */
-    QMGR_JOB *candidate_cache;         /* cached result from
-                                        * qmgr_job_candidate() */
-    time_t  candidate_cache_time;      /* when candidate_cache was last
-                                        * updated */
-    QMGR_TRANSPORT_LIST peers;         /* linkage */
-    char   *reason;                    /* why unavailable */
-};
-
-#define QMGR_TRANSPORT_STAT_DEAD       (1<<1)
-#define QMGR_TRANSPORT_STAT_BUSY       (1<<2)
-
-typedef void (*QMGR_TRANSPORT_ALLOC_NOTIFY) (QMGR_TRANSPORT *, VSTREAM *);
-extern QMGR_TRANSPORT *qmgr_transport_select(void);
-extern void qmgr_transport_alloc(QMGR_TRANSPORT *, QMGR_TRANSPORT_ALLOC_NOTIFY);
-extern void qmgr_transport_throttle(QMGR_TRANSPORT *, const char *);
-extern void qmgr_transport_unthrottle(QMGR_TRANSPORT *);
-extern QMGR_TRANSPORT *qmgr_transport_create(const char *);
-extern QMGR_TRANSPORT *qmgr_transport_find(const char *);
-
- /*
-  * Each next hop (e.g., a domain name) has its own queue of pending message
-  * transactions. The "todo" queue contains messages that are to be delivered
-  * to this next hop. When a message is elected for transmission, it is moved
-  * from the "todo" queue to the "busy" queue. Messages are taken from the
-  * "todo" queue in round-robin order.
-  */
-struct QMGR_ENTRY_LIST {
-    QMGR_ENTRY *next;
-    QMGR_ENTRY *prev;
-};
-
-struct QMGR_QUEUE {
-    char   *name;                      /* domain name */
-    int     todo_refcount;             /* queue entries (todo list) */
-    int     busy_refcount;             /* queue entries (busy list) */
-    int     window;                    /* slow open algorithm */
-    QMGR_TRANSPORT *transport;         /* transport linkage */
-    QMGR_ENTRY_LIST todo;              /* todo queue entries */
-    QMGR_ENTRY_LIST busy;              /* messages on the wire */
-    QMGR_QUEUE_LIST peers;             /* neighbor queues */
-    char   *reason;                    /* why unavailable */
-};
-
-#define        QMGR_QUEUE_TODO 1               /* waiting for service */
-#define QMGR_QUEUE_BUSY        2               /* recipients on the wire */
-
-extern int qmgr_queue_count;
-
-extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *);
-extern void qmgr_queue_done(QMGR_QUEUE *);
-extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *);
-extern void qmgr_queue_unthrottle(QMGR_QUEUE *);
-extern QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *, const char *);
-
- /*
-  * Structure for a recipient list. Initially, it just contains recipient
-  * addresses and file offsets. After the address resolver has done its work,
-  * each recipient is accompanied by a reference to a specific queues (which
-  * implies a specific transport). This is an extended version of similar
-  * information maintained by the recipient_list(3) module.
-  */
-struct QMGR_RCPT {
-    long    offset;                    /* REC_TYPE_RCPT byte */
-    char   *address;                   /* complete address */
-    QMGR_QUEUE *queue;                 /* resolved queue */
-};
-
-struct QMGR_RCPT_LIST {
-    QMGR_RCPT *info;
-    int     len;
-    int     avail;
-};
-
-extern void qmgr_rcpt_list_init(QMGR_RCPT_LIST *);
-extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *);
-extern void qmgr_rcpt_list_free(QMGR_RCPT_LIST *);
-
- /*
-  * Structure of one next-hop queue entry. In order to save some copying
-  * effort we allow multiple recipients per transaction.
-  */
-struct QMGR_ENTRY {
-    VSTREAM *stream;                   /* delivery process */
-    QMGR_MESSAGE *message;             /* message info */
-    QMGR_RCPT_LIST rcpt_list;          /* as many as it takes */
-    QMGR_QUEUE *queue;                 /* parent linkage */
-    QMGR_PEER *peer;                   /* parent linkage */
-    QMGR_ENTRY_LIST queue_peers;       /* per queue neighbor entries */
-    QMGR_ENTRY_LIST peer_peers;                /* per peer neighbor entries */
-};
-
-extern QMGR_ENTRY *qmgr_entry_select(QMGR_PEER *);
-extern void qmgr_entry_unselect(QMGR_ENTRY *);
-extern void qmgr_entry_done(QMGR_ENTRY *, int);
-extern QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *, QMGR_MESSAGE *);
-
- /*
-  * All common in-core information about a message is kept here. When all
-  * recipients have been tried the message file is linked to the "deferred"
-  * queue (some hosts not reachable), to the "bounce" queue (some recipients
-  * were rejected), and is then removed from the "active" queue.
-  */
-struct QMGR_MESSAGE {
-    int     flags;                     /* delivery problems */
-    int     qflags;                    /* queuing flags */
-    VSTREAM *fp;                       /* open queue file or null */
-    int     refcount;                  /* queue entries */
-    int     single_rcpt;               /* send one rcpt at a time */
-    long    arrival_time;              /* time when queued */
-    time_t  queued_time;               /* time when moved to the active
-                                        * queue */
-    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 */
-    char   *sender;                    /* complete address */
-    char   *errors_to;                 /* error report address */
-    char   *return_receipt;            /* confirm receipt address */
-    char   *filter_xport;              /* filtering transport */
-    char   *inspect_xport;             /* inspecting transport */
-    long    data_size;                 /* message content size */
-    long    rcpt_offset;               /* more recipients here */
-    long    unread_offset;             /* more unread recipients here */
-    QMGR_RCPT_LIST rcpt_list;          /* complete addresses */
-    int     rcpt_count;                        /* used recipient slots */
-    int     rcpt_limit;                        /* maximum read in-core */
-    int     rcpt_unread;               /* # of recipients left in queue file */
-    QMGR_JOB_LIST job_list;            /* jobs delivering this message (1
-                                        * per transport) */
-};
-
-#define QMGR_MESSAGE_LOCKED    ((QMGR_MESSAGE *) 1)
-
-extern int qmgr_message_count;
-extern int qmgr_recipient_count;
-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 *);
-
- /*
-  * Sometimes it's required to access the transport queues and entries on per
-  * message basis. That's what the QMGR_JOB structure is for - it groups all
-  * per message information within each transport using a list of QMGR_PEER
-  * structures. These structures in turn correspond with per message
-  * QMGR_QUEUE structure and list all per message QMGR_ENTRY structures.
-  */
-struct QMGR_PEER_LIST {
-    QMGR_PEER *next;
-    QMGR_PEER *prev;
-};
-
-struct QMGR_JOB {
-    QMGR_MESSAGE *message;             /* message delivered by this job */
-    QMGR_TRANSPORT *transport;         /* transport this job belongs to */
-    QMGR_JOB_LIST message_peers;       /* per message neighbor linkage */
-    QMGR_JOB_LIST transport_peers;     /* per transport neighbor linkage */
-    QMGR_JOB_LIST stack_peers;         /* transport stack linkage */
-    int     stack_level;               /* job stack nesting level (-1 means
-                                        * retired) */
-    struct HTABLE *peer_byname;                /* message job peers, indexed by
-                                        * domain */
-    QMGR_PEER_LIST peer_list;          /* list of message job peers */
-    int     slots_used;                        /* slots used during preemption */
-    int     slots_available;           /* slots available for preemption (in
-                                        * multiples of slot_cost) */
-    int     selected_entries;          /* # of entries selected for delivery
-                                        * so far */
-    int     read_entries;              /* # of entries read in-core so far */
-    int     rcpt_count;                        /* used recipient slots */
-    int     rcpt_limit;                        /* available recipient slots */
-};
-
-struct QMGR_PEER {
-    QMGR_JOB *job;                     /* job handling this peer */
-    QMGR_QUEUE *queue;                 /* queue corresponding with this peer */
-    int     refcount;                  /* peer entries */
-    QMGR_ENTRY_LIST entry_list;                /* todo message entries queued for
-                                        * this peer */
-    QMGR_PEER_LIST peers;              /* neighbor linkage */
-};
-
-extern QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *);
-extern QMGR_PEER *qmgr_peer_select(QMGR_JOB *);
-
-extern QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *, QMGR_TRANSPORT *);
-extern void qmgr_job_free(QMGR_JOB *);
-extern void qmgr_job_move_limits(QMGR_JOB *);
-
-extern QMGR_PEER *qmgr_peer_create(QMGR_JOB *, QMGR_QUEUE *);
-extern QMGR_PEER *qmgr_peer_find(QMGR_JOB *, QMGR_QUEUE *);
-extern void qmgr_peer_free(QMGR_PEER *);
-
- /*
-  * qmgr_defer.c
-  */
-extern void qmgr_defer_transport(QMGR_TRANSPORT *, const char *);
-extern void qmgr_defer_todo(QMGR_QUEUE *, const char *);
-extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *);
-
- /*
-  * qmgr_bounce.c
-  */
-extern void PRINTFLIKE(3, 4) qmgr_bounce_recipient(QMGR_MESSAGE *, QMGR_RCPT *, const char *,...);
-
- /*
-  * qmgr_deliver.c
-  */
-extern int qmgr_deliver_concurrency;
-extern void qmgr_deliver(QMGR_TRANSPORT *, VSTREAM *);
-
- /*
-  * qmgr_active.c
-  */
-extern void qmgr_active_feed(QMGR_SCAN *, const char *);
-extern void qmgr_active_drain(void);
-extern void qmgr_active_done(QMGR_MESSAGE *);
-
- /*
-  * qmgr_move.c
-  */
-extern void qmgr_move(const char *, const char *, time_t);
-
- /*
-  * qmgr_enable.c
-  */
-extern void qmgr_enable_all(void);
-extern void qmgr_enable_transport(QMGR_TRANSPORT *);
-extern void qmgr_enable_queue(QMGR_QUEUE *);
-
- /*
-  * Queue scan context.
-  */
-struct QMGR_SCAN {
-    char   *queue;                     /* queue name */
-    int     flags;                     /* private, this run */
-    int     nflags;                    /* private, next run */
-    struct SCAN_DIR *handle;           /* scan */
-};
-
- /*
-  * Flags that control queue scans or destination selection. These are
-  * similar to the QMGR_REQ_XXX request codes.
-  */
-#define QMGR_SCAN_START        (1<<0)          /* start now/restart when done */
-#define QMGR_SCAN_ALL  (1<<1)          /* all queue file time stamps */
-#define QMGR_FLUSH_DEAD        (1<<2)          /* all sites, all transports */
-
- /*
-  * qmgr_scan.c
-  */
-extern QMGR_SCAN *qmgr_scan_create(const char *);
-extern void qmgr_scan_request(QMGR_SCAN *, int);
-extern char *qmgr_scan_next(QMGR_SCAN *);
-
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
diff --git a/postfix/src/nqmgr/qmgr_active.c b/postfix/src/nqmgr/qmgr_active.c
deleted file mode 100644 (file)
index ec00584..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_active 3
-/* SUMMARY
-/*     active queue management
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     void    qmgr_active_feed(scan_info, queue_id)
-/*     QMGR_SCAN *scan_info;
-/*     const char *queue_id;
-/*
-/*     void    qmgr_active_drain()
-/*
-/*     int     qmgr_active_done(message)
-/*     QMGR_MESSAGE *message;
-/* DESCRIPTION
-/*     These functions maintain the active message queue: the set
-/*     of messages that the queue manager is actually working on.
-/*     The active queue is limited in size. Messages are drained
-/*     from the active queue by allocating a delivery process and
-/*     by delivering mail via that process.  Messages leak into the
-/*     active queue only when the active queue is small enough.
-/*     Damaged message files are saved to the "corrupt" directory.
-/*
-/*     qmgr_active_feed() inserts the named message file into
-/*     the active queue. Message files with the wrong name or
-/*     with other wrong properties are skipped but not removed.
-/*     The following queue flags are recognized, other flags being
-/*     ignored:
-/* .IP QMGR_SCAN_ALL
-/*     Examine all queue files. Normally, deferred queue files with
-/*     future time stamps are ignored, and incoming queue files with
-/*     future time stamps are frowned upon.
-/* .PP
-/*     qmgr_active_drain() allocates one delivery process.
-/*     Process allocation is asynchronous. Once the delivery
-/*     process is available, an attempt is made to deliver
-/*     a message via it. Message delivery is asynchronous, too.
-/*
-/*     qmgr_active_done() deals with a message after delivery
-/*     has been tried for all in-core recipients. If the message
-/*     was bounced, a bounce message is sent to the sender, or
-/*     to the Errors-To: address if one was specified.
-/*     If there are more on-file recipients, a new batch of
-/*     in-core recipients is read from the queue file. Otherwise,
-/*     if a delivery agent marked the queue file as corrupt,
-/*     the queue file is moved to the "corrupt" queue (surprise);
-/*     if at least one delivery failed, the message is moved
-/*     to the deferred queue. The time stamps of a deferred queue
-/*     file are set to the nearest wakeup time of its recipient
-/*     sites (if delivery failed due to a problem with a next-hop
-/*     host), are set into the future by the amount of time the
-/*     message was queued (per-message exponential backoff), or are set
-/*     into the future by a minimal backoff time, whichever is more.
-/*     The minimal_backoff_time parameter specifies the minimal
-/*     amount of time between delivery attempts; maximal_backoff_time
-/*     specifies an upper limit.
-/* DIAGNOSTICS
-/*     Fatal: queue file access failures, out of memory.
-/*     Panic: interface violations, internal consistency errors.
-/*     Warnings: corrupt message file. A corrupt message is saved
-/*     to the "corrupt" queue for further inspection.
-/* 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 <dirent.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <utime.h>
-#include <errno.h>
-
-#ifndef S_IRWXU                                /* What? no POSIX system? */
-#define S_IRWXU 0700
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <events.h>
-#include <mymalloc.h>
-#include <vstream.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-#include <mail_open_ok.h>
-#include <mail_queue.h>
-#include <recipient_list.h>
-#include <bounce.h>
-#include <defer.h>
-#include <abounce.h>
-#include <rec_type.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
- /*
-  * A bunch of call-back routines.
-  */
-static void qmgr_active_done_2_bounce_flush(int, char *);
-static void qmgr_active_done_2_generic(QMGR_MESSAGE *);
-static void qmgr_active_done_3_defer_flush(int, char *);
-static void qmgr_active_done_3_defer_warn(int, char *);
-static void qmgr_active_done_3_generic(QMGR_MESSAGE *);
-
-/* qmgr_active_corrupt - move corrupted file out of the way */
-
-static void qmgr_active_corrupt(const char *queue_id)
-{
-    char   *myname = "qmgr_active_corrupt";
-
-    if (mail_queue_rename(queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT)) {
-       if (errno != ENOENT)
-           msg_fatal("%s: save corrupt file queue %s id %s: %m",
-                     myname, MAIL_QUEUE_ACTIVE, queue_id);
-       msg_warn("%s: save corrupt file queue %s id %s: %m",
-                myname, MAIL_QUEUE_ACTIVE, queue_id);
-    } else {
-       msg_warn("corrupt file queue %s id %s", MAIL_QUEUE_ACTIVE, queue_id);
-    }
-}
-
-/* qmgr_active_defer - defer queue file */
-
-static void qmgr_active_defer(const char *queue_name, const char *queue_id,
-                                     const char *dest_queue, int delay)
-{
-    char   *myname = "qmgr_active_defer";
-    const char *path;
-    struct utimbuf tbuf;
-
-    if (msg_verbose)
-       msg_info("wakeup %s after %ld secs", queue_id, (long) delay);
-
-    tbuf.actime = tbuf.modtime = event_time() + delay;
-    path = mail_queue_path((VSTRING *) 0, queue_name, queue_id);
-    if (utime(path, &tbuf) < 0)
-       msg_fatal("%s: update %s time stamps: %m", myname, path);
-    if (mail_queue_rename(queue_id, queue_name, dest_queue)) {
-       if (errno != ENOENT)
-           msg_fatal("%s: rename %s from %s to %s: %m", myname,
-                     queue_id, queue_name, dest_queue);
-       msg_warn("%s: rename %s from %s to %s: %m", myname,
-                queue_id, queue_name, dest_queue);
-    } else if (msg_verbose) {
-       msg_info("%s: defer %s", myname, queue_id);
-    }
-}
-
-/* qmgr_active_feed - feed one message into active queue */
-
-void    qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id)
-{
-    char   *myname = "qmgr_active_feed";
-    QMGR_MESSAGE *message;
-    struct stat st;
-    const char *path;
-
-    if (strcmp(scan_info->queue, MAIL_QUEUE_ACTIVE) == 0)
-       msg_panic("%s: bad queue %s", myname, scan_info->queue);
-    if (msg_verbose)
-       msg_info("%s: queue %s", myname, scan_info->queue);
-
-    /*
-     * Make sure this is something we are willing to open.
-     */
-    if (mail_open_ok(scan_info->queue, queue_id, &st, &path) == MAIL_OPEN_NO)
-       return;
-
-    if (msg_verbose)
-       msg_info("%s: %s", myname, path);
-
-    /*
-     * Skip files that have time stamps into the future. They need to cool
-     * 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 (msg_verbose)
-           msg_info("%s: skip %s (%ld seconds)", myname, queue_id,
-                    (long) (st.st_mtime - event_time()));
-       return;
-    }
-
-    /*
-     * Move the message to the active queue. File access errors are fatal.
-     */
-    if (mail_queue_rename(queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE)) {
-       if (errno != ENOENT)
-           msg_fatal("%s: %s: rename from %s to %s: %m", myname,
-                     queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE);
-       msg_warn("%s: %s: rename from %s to %s: %m", myname,
-                queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE);
-       return;
-    }
-
-    /*
-     * Extract envelope information: sender and recipients. At this point,
-     * mail addresses have been processed by the cleanup service so they
-     * should be in canonical form. Generate requests to deliver this
-     * message.
-     * 
-     * Throwing away queue files seems bad, especially when they made it this
-     * far into the mail system. Therefore we save bad files to a separate
-     * directory for further inspection.
-     * 
-     * After queue manager restart it is possible that a queue file is still
-     * being delivered. In that case (the file is locked), defer delivery by
-     * a minimal amount of time.
-     */
-    if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id,
-                                     scan_info->flags)) == 0) {
-       qmgr_active_corrupt(queue_id);
-    } else if (message == QMGR_MESSAGE_LOCKED) {
-       qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, MAIL_QUEUE_INCOMING, 60);
-    } else {
-
-       /*
-        * Special case if all recipients were already delivered. Send any
-        * bounces and clean up.
-        */
-       if (message->refcount == 0)
-           qmgr_active_done(message);
-    }
-}
-
-/* qmgr_active_done - dispose of message after recipients have been tried */
-
-void    qmgr_active_done(QMGR_MESSAGE *message)
-{
-    char   *myname = "qmgr_active_done";
-    struct stat st;
-
-    if (msg_verbose)
-       msg_info("%s: %s", myname, message->queue_id);
-
-    /*
-     * During a previous iteration, an attempt to bounce this message may
-     * have failed, so there may still be a bounce log lying around. XXX By
-     * groping around in the bounce queue, we're trespassing on the bounce
-     * service's territory. But doing so is more robust than depending on the
-     * bounce daemon to do the lookup for us, and for us to do the deleting
-     * after we have received a successful status from the bounce service.
-     * The bounce queue directory blocks are most likely in memory anyway. If
-     * these lookups become a performance problem we will have to build an
-     * in-core cache into the bounce daemon.
-     * 
-     * Don't bounce when the bounce log is empty. The bounce process obviously
-     * failed, and the delivery agent will have requested that the message be
-     * deferred.
-     * 
-     * Bounces are sent asynchronously to avoid stalling while the cleanup
-     * daemon waits for the qmgr to accept the "new mail" trigger.
-     */
-    if (stat(mail_queue_path((VSTRING *) 0, MAIL_QUEUE_BOUNCE, message->queue_id), &st) == 0) {
-       if (st.st_size == 0) {
-           if (mail_queue_remove(MAIL_QUEUE_BOUNCE, message->queue_id))
-               msg_fatal("remove %s %s: %m",
-                         MAIL_QUEUE_BOUNCE, message->queue_id);
-       } else {
-           if (msg_verbose)
-               msg_info("%s: bounce %s", myname, message->queue_id);
-           abounce_flush(BOUNCE_FLAG_KEEP,
-                         message->queue_name,
-                         message->queue_id,
-                         message->errors_to,
-                         qmgr_active_done_2_bounce_flush,
-                         (char *) message);
-           return;
-       }
-    }
-
-    /*
-     * Asynchronous processing does not reach this point.
-     */
-    qmgr_active_done_2_generic(message);
-}
-
-/* qmgr_active_done_2_bounce_flush - process abounce_flush() status */
-
-static void qmgr_active_done_2_bounce_flush(int status, char *context)
-{
-    QMGR_MESSAGE *message = (QMGR_MESSAGE *) context;
-
-    /*
-     * Process abounce_flush() status and continue processing.
-     */
-    message->flags |= status;
-    qmgr_active_done_2_generic(message);
-}
-
-/* qmgr_active_done_2_generic - continue processing */
-
-static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
-{
-    char   *myname = "qmgr_active_done_2_generic";
-    const char *path;
-    struct stat st;
-
-    /*
-     * A delivery agent marks a queue file as corrupt by changing its
-     * attributes, and by pretending that delivery was deferred.
-     */
-    if (message->flags
-       && !mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path)) {
-       qmgr_active_corrupt(message->queue_id);
-       qmgr_message_free(message);
-       return;
-    }
-
-    /*
-     * If we did not read all recipients from this file, go read some more,
-     * but remember whether some recipients have to be tried again.
-     * 
-     * Throwing away queue files seems bad, especially when they made it this
-     * far into the mail system. Therefore we save bad files to a separate
-     * directory for further inspection by a human being.
-     */
-    if (message->rcpt_offset > 0) {
-       if (qmgr_message_realloc(message) == 0) {
-           qmgr_active_corrupt(message->queue_id);
-           qmgr_message_free(message);
-       } else {
-           if (message->refcount == 0)
-               qmgr_active_done(message);      /* recurse for consistency */
-       }
-       return;
-    }
-
-    /*
-     * If we get to this point we have tried all recipients for this message.
-     * If the message is too old, try to bounce it.
-     * 
-     * Bounces are sent asynchronously to avoid stalling while the cleanup
-     * daemon waits for the qmgr to accept the "new mail" trigger.
-     */
-    if (message->flags) {
-       if (event_time() > message->arrival_time + var_max_queue_time) {
-           if (msg_verbose)
-               msg_info("%s: too old, bouncing %s", myname, message->queue_id);
-           adefer_flush(BOUNCE_FLAG_KEEP,
-                        message->queue_name,
-                        message->queue_id,
-                        message->errors_to,
-                        qmgr_active_done_3_defer_flush,
-                        (char *) message);
-           return;
-       } 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);
-           adefer_warn(BOUNCE_FLAG_KEEP,
-                       message->queue_name,
-                       message->queue_id,
-                       message->errors_to,
-                       qmgr_active_done_3_defer_warn,
-                       (char *) message);
-           return;
-       }
-    }
-
-    /*
-     * Asynchronous processing does not reach this point.
-     */
-    qmgr_active_done_3_generic(message);
-}
-
-/* qmgr_active_done_3_defer_warn - continue after adefer_warn() completion */
-
-static void qmgr_active_done_3_defer_warn(int status, char *context)
-{
-    QMGR_MESSAGE *message = (QMGR_MESSAGE *) context;
-
-    /*
-     * Process adefer_warn() completion status and continue processing.
-     */
-    if (status == 0)
-       qmgr_message_update_warn(message);
-    qmgr_active_done_3_generic(message);
-}
-
-/* qmgr_active_done_3_defer_flush - continue after adefer_flush() completion */
-
-static void qmgr_active_done_3_defer_flush(int status, char *context)
-{
-    QMGR_MESSAGE *message = (QMGR_MESSAGE *) context;
-
-    /*
-     * Process adefer_flush() status and continue processing.
-     */
-    message->flags = status;
-    qmgr_active_done_3_generic(message);
-}
-
-/* qmgr_active_done_3_generic - continue processing */
-
-static void qmgr_active_done_3_generic(QMGR_MESSAGE *message)
-{
-    char   *myname = "qmgr_active_done_3_generic";
-    int     delay;
-
-    /*
-     * Some recipients need to be tried again. Move the queue file time
-     * stamps into the future by the amount of time that the message is
-     * delayed, and move the message to the deferred queue. Impose minimal
-     * and maximal backoff times.
-     * 
-     * Since we look at actual time in queue, not time since last delivery
-     * attempt, backoff times will be distributed. However, we can still see
-     * spikes in delivery activity because the interval between deferred
-     * queue scans is finite.
-     */
-    if (message->flags) {
-       if (message->arrival_time > 0) {
-           delay = event_time() - message->arrival_time;
-           if (delay > var_max_backoff_time)
-               delay = var_max_backoff_time;
-           if (delay < var_min_backoff_time)
-               delay = var_min_backoff_time;
-       } else {
-           delay = var_min_backoff_time;
-       }
-       qmgr_active_defer(message->queue_name, message->queue_id,
-                         MAIL_QUEUE_DEFERRED, delay);
-    }
-
-    /*
-     * All recipients done. Remove the queue file.
-     */
-    else {
-       if (mail_queue_remove(message->queue_name, message->queue_id)) {
-           if (errno != ENOENT)
-               msg_fatal("%s: remove %s from %s: %m", myname,
-                         message->queue_id, message->queue_name);
-           msg_warn("%s: remove %s from %s: %m", myname,
-                    message->queue_id, message->queue_name);
-       } else if (msg_verbose) {
-           msg_info("%s: remove %s", myname, message->queue_id);
-       }
-    }
-
-    /*
-     * Finally, delete the in-core message structure.
-     */
-    qmgr_message_free(message);
-}
-
-/* qmgr_active_drain - drain active queue by allocating a delivery process */
-
-void    qmgr_active_drain(void)
-{
-    QMGR_TRANSPORT *transport;
-
-    /*
-     * Allocate one delivery process for every transport with pending mail.
-     * The process allocation completes asynchronously.
-     */
-    while ((transport = qmgr_transport_select()) != 0) {
-       if (msg_verbose)
-           msg_info("qmgr_active_drain: allocate %s", transport->name);
-       qmgr_transport_alloc(transport, qmgr_deliver);
-    }
-}
diff --git a/postfix/src/nqmgr/qmgr_bounce.c b/postfix/src/nqmgr/qmgr_bounce.c
deleted file mode 100644 (file)
index e8f0140..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_bounce
-/* SUMMARY
-/*     deal with mail that will not be delivered
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_QUEUE *qmgr_bounce_recipient(message, recipient, format, ...)
-/*     QMGR_MESSAGE *message;
-/*     QMGR_RCPT *recipient;
-/*     const char *format;
-/* DESCRIPTION
-/*     qmgr_bounce_recipient() produces a bounce log record.
-/*     Once the bounce record is written successfully, the recipient
-/*     is marked as done. When the bounce record cannot be written,
-/*     the message structure is updated to reflect that the mail is
-/*     deferred.
-/*
-/*     Arguments:
-/* .IP message
-/*     Open queue file with the message being bounced.
-/* .IP recipient
-/*     The recipient that will not be delivered.
-/* .IP format
-/*     Free-format text that describes why delivery will not happen.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure. Fatal: out of memory.
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdarg.h>
-
-/* Utility library. */
-
-/* Global library. */
-
-#include <bounce.h>
-#include <deliver_completed.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_bounce_recipient - bounce one message recipient */
-
-void    qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
-                                     const char *format,...)
-{
-    va_list ap;
-    int     status;
-
-    va_start(ap, format);
-    status = vbounce_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                           recipient->address, "none",
-                           message->arrival_time, format, ap);
-    va_end(ap);
-
-    if (status == 0)
-       deliver_completed(message->fp, recipient->offset);
-    else
-       message->flags |= status;
-}
diff --git a/postfix/src/nqmgr/qmgr_defer.c b/postfix/src/nqmgr/qmgr_defer.c
deleted file mode 100644 (file)
index 72d30aa..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_defer
-/* SUMMARY
-/*     deal with mail that must be delivered later
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     void    qmgr_defer_recipient(message, address, reason)
-/*     QMGR_MESSAGE *message;
-/*     const char *address;
-/*     const char *reason;
-/*
-/*     void    qmgr_defer_todo(queue, reason)
-/*     QMGR_QUEUE *queue;
-/*     const char *reason;
-/*
-/*     QMGR_QUEUE *qmgr_defer_transport(transport, reason)
-/*     QMGR_TRANSPORT *transport;
-/*     const char *reason;
-/* DESCRIPTION
-/*     qmgr_defer_recipient() defers delivery of the named message to
-/*     the named recipient. It updates the message structure and writes
-/*     a log entry.
-/*
-/*     qmgr_defer_todo() iterates over all "todo" deliveries queued for
-/*     the named site, and calls qmgr_defer_recipient() for each recipient
-/*     found.  Side effects caused by qmgr_entry_done(), qmgr_queue_done(),
-/*     and by qmgr_active_done(): in-core queue entries will disappear,
-/*     in-core queues may disappear, in-core and on-disk messages may
-/*     disappear, bounces may be sent, new in-core queues, queue entries
-/*     and recipients may appear.
-/*
-/*     qmgr_defer_transport() calls qmgr_defer_todo() for each queue
-/*     that depends on the named transport. See there for side effects.
-/*
-/*     Arguments:
-/* .IP recipient
-/*     A recipient address; used for logging purposes, and for updating
-/*     the message-specific \fIdefer\fR log.
-/* .IP queue
-/*     Specifies a queue with delivery requests for a specific next-hop
-/*     host (or local user).
-/* .IP transport
-/*     Specifies a message delivery transport.
-/* .IP reason
-/*     Free-format text that describes why delivery is deferred; this
-/*     used for logging purposes, and for updating the message-specific
-/*     \fIdefer\fR log.
-/* BUGS
-/*     The side effects of calling this routine are quite dramatic.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure. Fatal: out of memory.
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstream.h>
-
-/* Global library. */
-
-#include <defer.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_defer_transport - defer todo entries for named transport */
-
-void    qmgr_defer_transport(QMGR_TRANSPORT *transport, const char *reason)
-{
-    char   *myname = "qmgr_defer_transport";
-    QMGR_QUEUE *queue;
-    QMGR_QUEUE *next;
-
-    /*
-     * Sanity checks.
-     */
-    if (reason == 0)
-       msg_panic("%s: null reason", myname);
-    if (msg_verbose)
-       msg_info("defer transport %s: %s", transport->name, reason);
-
-    /*
-     * Proceed carefully. Queues may disappear as a side effect.
-     */
-    for (queue = transport->queue_list.next; queue; queue = next) {
-       next = queue->peers.next;
-       qmgr_defer_todo(queue, reason);
-    }
-}
-
-/* qmgr_defer_todo - defer all todo queue entries for specific site */
-
-void    qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason)
-{
-    char   *myname = "qmgr_defer_todo";
-    QMGR_ENTRY *entry;
-    QMGR_ENTRY *next;
-    QMGR_MESSAGE *message;
-    QMGR_RCPT *recipient;
-    int     nrcpt;
-
-    /*
-     * Sanity checks.
-     */
-    if (reason == 0)
-       msg_panic("%s: null reason", myname);
-    if (msg_verbose)
-       msg_info("defer site %s: %s", queue->name, reason);
-
-    /*
-     * Proceed carefully. Queue entries will disappear as a side effect.
-     */
-    for (entry = queue->todo.next; entry != 0; entry = next) {
-       next = entry->queue_peers.next;
-       message = entry->message;
-       for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
-           recipient = entry->rcpt_list.info + nrcpt;
-           qmgr_defer_recipient(message, recipient->address, reason);
-       }
-       qmgr_entry_done(entry, QMGR_QUEUE_TODO);
-    }
-}
-
-/* qmgr_defer_recipient - defer delivery of specific recipient */
-
-void    qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address,
-                                    const char *reason)
-{
-    char   *myname = "qmgr_defer_recipient";
-
-    /*
-     * Sanity checks.
-     */
-    if (reason == 0)
-       msg_panic("%s: reason 0", myname);
-
-    /*
-     * Update the message structure and log the message disposition.
-     */
-    message->flags |= defer_append(BOUNCE_FLAG_KEEP, message->queue_id,
-                                  address, "none", message->arrival_time,
-                                  "%s", reason);
-}
diff --git a/postfix/src/nqmgr/qmgr_deliver.c b/postfix/src/nqmgr/qmgr_deliver.c
deleted file mode 100644 (file)
index 3c47974..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_deliver 3
-/* SUMMARY
-/*     deliver one pe-site queue entry to that site
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     int     qmgr_deliver_concurrency;
-/*
-/*     int     qmgr_deliver(transport, fp)
-/*     QMGR_TRANSPORT *transport;
-/*     VSTREAM *fp;
-/* DESCRIPTION
-/*     This module implements the client side of the `queue manager
-/*     to delivery agent' protocol. The queue manager uses
-/*     asynchronous I/O so that it can drive multiple delivery
-/*     agents in parallel. Depending on the outcome of a delivery
-/*     attempt, the status of messages, queues and transports is
-/*     updated.
-/*
-/*     qmgr_deliver_concurrency is a global counter that says how
-/*     many delivery processes are in use. This can be used, for
-/*     example, to control the size of the `active' message queue.
-/*
-/*     qmgr_deliver() executes when a delivery process announces its
-/*     availability for the named transport. It arranges for delivery
-/*     of a suitable queue entry.  The \fIfp\fR argument specifies a
-/*     stream that is connected to the delivery process. Upon completion
-/*     of delivery (successful or not), the stream is closed, so that the
-/*     delivery process is released.
-/* DIAGNOSTICS
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <time.h>
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <events.h>
-#include <iostuff.h>
-
-/* Global library. */
-
-#include <mail_queue.h>
-#include <mail_proto.h>
-#include <recipient_list.h>
-#include <mail_params.h>
-#include <deliver_request.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-int     qmgr_deliver_concurrency;
-
- /*
-  * Message delivery status codes.
-  */
-#define DELIVER_STAT_OK                0       /* all recipients delivered */
-#define DELIVER_STAT_DEFER     1       /* try some recipients later */
-#define DELIVER_STAT_CRASH     2       /* mailer internal problem */
-
-/* qmgr_deliver_initial_reply - retrieve initial delivery process response */
-
-static int qmgr_deliver_initial_reply(VSTREAM *stream)
-{
-    int     stat;
-
-    if (peekfd(vstream_fileno(stream)) < 0) {
-       msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
-       return (DELIVER_STAT_CRASH);
-    } else if (mail_scan(stream, "%d", &stat) != 1) {
-       msg_warn("%s: malformed response", VSTREAM_PATH(stream));
-       return (DELIVER_STAT_CRASH);
-    } else {
-       return (stat ? DELIVER_STAT_DEFER : 0);
-    }
-}
-
-/* qmgr_deliver_final_reply - retrieve final delivery process response */
-
-static int qmgr_deliver_final_reply(VSTREAM *stream, VSTRING *reason)
-{
-    int     stat;
-
-    if (peekfd(vstream_fileno(stream)) < 0) {
-       msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
-       return (DELIVER_STAT_CRASH);
-    } else if (mail_scan(stream, "%s %d", reason, &stat) != 2) {
-       msg_warn("%s: malformed response", VSTREAM_PATH(stream));
-       return (DELIVER_STAT_CRASH);
-    } else {
-       return (stat ? DELIVER_STAT_DEFER : 0);
-    }
-}
-
-/* qmgr_deliver_send_request - send delivery request to delivery process */
-
-static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
-{
-    QMGR_RCPT_LIST list = entry->rcpt_list;
-    QMGR_RCPT *recipient;
-    QMGR_MESSAGE *message = entry->message;
-    char   *cp;
-
-    /*
-     * With local delivery, the queue name is user@nexthop, so that we can
-     * implement per-recipient concurrency limits. The delivery agent
-     * protocol expects nexthop only.
-     */
-    mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld",
-         message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT,
-              message->queue_name, message->queue_id,
-              message->data_offset, message->data_size,
-           (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 :
-              entry->queue->name, message->sender,
-              message->errors_to, message->return_receipt,
-              message->arrival_time);
-    for (recipient = list.info; recipient < list.info + list.len; recipient++)
-       mail_print(stream, "%ld %s", recipient->offset, recipient->address);
-    mail_print(stream, "%s", "0");
-    if (vstream_fflush(stream) != 0) {
-       msg_warn("write to process (%s): %m", entry->queue->transport->name);
-       return (-1);
-    } else {
-       if (msg_verbose)
-           msg_info("qmgr_deliver: site `%s'", entry->queue->name);
-       return (0);
-    }
-}
-
-/* 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)
-{
-    QMGR_ENTRY *entry = (QMGR_ENTRY *) context;
-    QMGR_QUEUE *queue = entry->queue;
-    QMGR_TRANSPORT *transport = queue->transport;
-    QMGR_MESSAGE *message = entry->message;
-    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
-     * only when a site 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.
-     */
-    status = qmgr_deliver_final_reply(entry->stream, reason);
-
-    /*
-     * The mail delivery process failed for some reason (although delivery
-     * may have been successful). Back off with this transport type for a
-     * while. Dispose of queue entries for this transport that await
-     * selection (the todo lists). Stay away from queue entries that have
-     * been selected (the busy lists), or we would have dangling pointers.
-     * The queue itself won't go away before we dispose of the current queue
-     * entry.
-     */
-    if (status == DELIVER_STAT_CRASH) {
-       message->flags |= DELIVER_STAT_DEFER;
-       qmgr_transport_throttle(transport, "unknown mail transport error");
-       qmgr_defer_transport(transport, transport->reason);
-    }
-
-    /*
-     * This message must be tried again.
-     * 
-     * If we have a problem talking to this site, back off with this site for a
-     * while; dispose of queue entries for this site that await selection
-     * (the todo list); stay away from queue entries that have been selected
-     * (the busy list), or we would have dangling pointers. The queue itself
-     * won't go away before we dispose of the current queue entry.
-     */
-    if (status == DELIVER_STAT_DEFER) {
-       message->flags |= DELIVER_STAT_DEFER;
-       if (VSTRING_LEN(reason)) {
-           qmgr_queue_throttle(queue, vstring_str(reason));
-           if (queue->window == 0)
-               qmgr_defer_todo(queue, queue->reason);
-       }
-    }
-
-    /*
-     * No problems detected. Mark the transport and queue as alive. The queue
-     * itself won't go away before we dispose of the current queue entry.
-     */
-    if (status == 0) {
-       qmgr_transport_unthrottle(transport);
-       qmgr_queue_unthrottle(queue);
-    }
-
-    /*
-     * Release the delivery process, and give some other queue entry a chance
-     * to be delivered. When all recipients for a message have been tried,
-     * decide what to do next with this message: defer, bounce, delete.
-     */
-    event_disable_readwrite(vstream_fileno(entry->stream));
-    if (vstream_fclose(entry->stream) != 0)
-       msg_warn("qmgr_deliver_update: close delivery stream: %m");
-    entry->stream = 0;
-    qmgr_deliver_concurrency--;
-    qmgr_entry_done(entry, QMGR_QUEUE_BUSY);
-    vstring_free(reason);
-}
-
-/* qmgr_deliver - deliver one per-site queue entry */
-
-void    qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream)
-{
-    QMGR_ENTRY *entry;
-
-    /*
-     * Find out if this delivery process is really available. Once elected,
-     * the delivery process is supposed to express its happiness. If there is
-     * a problem, wipe the pending deliveries for this transport. This
-     * routine runs in response to an external event, so it does not run
-     * while some other queue manipulation is happening.
-     */
-    if (qmgr_deliver_initial_reply(stream) != 0) {
-       qmgr_transport_throttle(transport, "mail transport unavailable");
-       qmgr_defer_transport(transport, transport->reason);
-       (void) vstream_fclose(stream);
-       return;
-    }
-
-    /*
-     * Find a suitable queue entry. Things may have changed since this
-     * transport was allocated. If no suitable entry is found,
-     * unceremoniously disconnect from the delivery process. The delivery
-     * agent request reading routine is prepared for the queue manager to
-     * change its mind for no apparent reason.
-     */
-    if ((entry = qmgr_job_entry_select(transport)) == 0) {
-       (void) vstream_fclose(stream);
-       return;
-    }
-
-    /*
-     * Send the queue file info and recipient info to the delivery process.
-     * If there is a problem, wipe the pending deliveries for this transport.
-     * This routine runs in response to an external event, so it does not run
-     * while some other queue manipulation is happening.
-     */
-    if (qmgr_deliver_send_request(entry, stream) < 0) {
-       qmgr_entry_unselect(entry);
-       qmgr_transport_throttle(transport, "mail transport unavailable");
-       qmgr_defer_transport(transport, transport->reason);
-       /* warning: entry may be a dangling pointer here */
-       (void) vstream_fclose(stream);
-       return;
-    }
-
-    /*
-     * If we get this far, go wait for the delivery status report.
-     */
-    qmgr_deliver_concurrency++;
-    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_daemon_timeout);
-}
diff --git a/postfix/src/nqmgr/qmgr_enable.c b/postfix/src/nqmgr/qmgr_enable.c
deleted file mode 100644 (file)
index 5f0c384..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_enable
-/* SUMMARY
-/*     enable dead transports or sites
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     void    qmgr_enable_queue(queue)
-/*     QMGR_QUEUE *queue;
-/*
-/*     QMGR_QUEUE *qmgr_enable_transport(transport)
-/*     QMGR_TRANSPORT *transport;
-/*
-/*     void    qmgr_enable_all(void)
-/* DESCRIPTION
-/*     This module purges dead in-core state information, effectively
-/*     re-enabling delivery.
-/*
-/*     qmgr_enable_queue() enables deliveries to the named dead site.
-/*     Empty queues are destroyed. The existed solely to indicate that
-/*     a site is dead.
-/*
-/*     qmgr_enable_transport() enables deliveries via the specified
-/*     transport, and calls qmgr_enable_queue() for each destination
-/*     on that transport.  Empty queues are destroyed.
-/*
-/*     qmgr_enable_all() enables all transports and queues.
-/*     See above for the side effects caused by doing this.
-/* BUGS
-/*     The side effects of calling this module can be quite dramatic.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure. Fatal: out of memory.
-/* 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 <vstream.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_enable_all - enable transports and queues */
-
-void    qmgr_enable_all(void)
-{
-    QMGR_TRANSPORT *xport;
-
-    if (msg_verbose)
-       msg_info("qmgr_enable_all");
-
-    /*
-     * The number of transports does not change as a side effect, so this can
-     * be a straightforward loop.
-     */
-    for (xport = qmgr_transport_list.next; xport; xport = xport->peers.next)
-       qmgr_enable_transport(xport);
-}
-
-/* qmgr_enable_transport - defer todo entries for named transport */
-
-void    qmgr_enable_transport(QMGR_TRANSPORT *transport)
-{
-    QMGR_QUEUE *queue;
-    QMGR_QUEUE *next;
-
-    /*
-     * Proceed carefully. Queues may disappear as a side effect.
-     */
-    if (transport->flags & QMGR_TRANSPORT_STAT_DEAD) {
-       if (msg_verbose)
-           msg_info("enable transport %s", transport->name);
-       qmgr_transport_unthrottle(transport);
-    }
-    for (queue = transport->queue_list.next; queue; queue = next) {
-       next = queue->peers.next;
-       qmgr_enable_queue(queue);
-    }
-}
-
-/* qmgr_enable_queue - enable and possibly delete queue */
-
-void    qmgr_enable_queue(QMGR_QUEUE *queue)
-{
-    if (queue->window == 0) {
-       if (msg_verbose)
-           msg_info("enable site %s/%s", queue->transport->name, queue->name);
-       qmgr_queue_unthrottle(queue);
-    }
-    if (queue->todo.next == 0 && queue->busy.next == 0)
-       qmgr_queue_done(queue);
-}
diff --git a/postfix/src/nqmgr/qmgr_entry.c b/postfix/src/nqmgr/qmgr_entry.c
deleted file mode 100644 (file)
index 079ae7a..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_entry 3
-/* SUMMARY
-/*     per-site queue entries
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_ENTRY *qmgr_entry_create(peer, message)
-/*      QMGR_PEER *peer;
-/*     QMGR_MESSAGE *message;
-/*
-/*     void    qmgr_entry_done(entry, which)
-/*     QMGR_ENTRY *entry;
-/*     int     which;
-/*
-/*     QMGR_ENTRY *qmgr_entry_select(queue)
-/*     QMGR_QUEUE *queue;
-/*
-/*     void    qmgr_entry_unselect(queue, entry)
-/*     QMGR_QUEUE *queue;
-/*     QMGR_ENTRY *entry;
-/* DESCRIPTION
-/*     These routines add/delete/manipulate per-site message
-/*     delivery requests.
-/*
-/*     qmgr_entry_create() creates an entry for the named peer and message,
-/*      and appends the entry to the peer's list and its queue's todo list.
-/*     Filling in and cleaning up the recipients is the responsibility
-/*     of the caller.
-/*
-/*     qmgr_entry_done() discards a per-site queue entry.  The
-/*     \fIwhich\fR argument is either QMGR_QUEUE_BUSY for an entry
-/*     of the site's `busy' list (i.e. queue entries that have been
-/*     selected for actual delivery), or QMGR_QUEUE_TODO for an entry
-/*     of the site's `todo' list (i.e. queue entries awaiting selection
-/*     for actual delivery).
-/*
-/*     qmgr_entry_done() discards its peer structure when the peer
-/*      is not referenced anymore.
-/*
-/*     qmgr_entry_done() triggers cleanup of the per-site queue when
-/*     the site has no pending deliveries, and the site is either
-/*     alive, or the site is dead and the number of in-core queues
-/*     exceeds a configurable limit (see qmgr_queue_done()).
-/*
-/*     qmgr_entry_done() triggers special action when the last in-core
-/*     queue entry for a message is done with: either read more
-/*     recipients from the queue file, delete the queue file, or move
-/*     the queue file to the deferred queue; send bounce reports to the
-/*     message originator (see qmgr_active_done()).
-/*
-/*     qmgr_entry_select() selects first entry from the named
-/*     per-site queue's `todo' list for actual delivery. The entry is
-/*     moved to the queue's `busy' list: the list of messages being
-/*     delivered. The entry is also removed from its peer list.
-/*
-/*     qmgr_entry_unselect() takes the named entry off the named
-/*     per-site queue's `busy' list and moves it to the queue's
-/*     `todo' list. The entry is also appended to its peer list again.
-/* DIAGNOSTICS
-/*     Panic: interface violations, internal inconsistencies.
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdlib.h>
-#include <time.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <events.h>
-#include <vstream.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_entry_select - select queue entry for delivery */
-
-QMGR_ENTRY *qmgr_entry_select(QMGR_PEER *peer)
-{
-    QMGR_ENTRY *entry;
-    QMGR_QUEUE *queue;
-
-    if ((entry = peer->entry_list.next) != 0) {
-       queue = entry->queue;
-       QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers);
-       queue->todo_refcount--;
-       QMGR_LIST_APPEND(queue->busy, entry, queue_peers);
-       queue->busy_refcount++;
-       QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers);
-       peer->job->selected_entries++;
-    }
-    return (entry);
-}
-
-/* qmgr_entry_unselect - unselect queue entry for delivery */
-
-void    qmgr_entry_unselect(QMGR_ENTRY *entry)
-{
-    QMGR_PEER *peer = entry->peer;
-    QMGR_QUEUE *queue = entry->queue;
-
-    QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry, queue_peers);
-    queue->busy_refcount--;
-    QMGR_LIST_APPEND(queue->todo, entry, queue_peers);
-    queue->todo_refcount++;
-    QMGR_LIST_APPEND(peer->entry_list, entry, peer_peers);
-    peer->job->selected_entries--;
-}
-
-/* qmgr_entry_done - dispose of queue entry */
-
-void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
-{
-    QMGR_QUEUE *queue = entry->queue;
-    QMGR_MESSAGE *message = entry->message;
-    QMGR_PEER *peer = entry->peer;
-    QMGR_JOB *sponsor,
-           *job = peer->job;
-
-    /*
-     * Take this entry off the in-core queue.
-     */
-    if (entry->stream != 0)
-       msg_panic("qmgr_entry_done: file is open");
-    if (which == QMGR_QUEUE_BUSY) {
-       QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry, queue_peers);
-       queue->busy_refcount--;
-    } else if (which == QMGR_QUEUE_TODO) {
-       QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers);
-       job->selected_entries++;
-       QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers);
-       queue->todo_refcount--;
-    } else {
-       msg_panic("qmgr_entry_done: bad queue spec: %d", which);
-    }
-
-    /*
-     * Decrease the in-core recipient counts and free the recipient list and
-     * the structure itself.
-     */
-    job->rcpt_count -= entry->rcpt_list.len;
-    message->rcpt_count -= entry->rcpt_list.len;
-    qmgr_recipient_count -= entry->rcpt_list.len;
-    qmgr_rcpt_list_free(&entry->rcpt_list);
-    myfree((char *) entry);
-
-    /*
-     * Make sure that the transport of any retired or finishing job that
-     * donated recipient slots to this message gets them back first. Then, if
-     * possible, pass the remaining unused recipient slots to the next job in
-     * the job list.
-     */
-    for (sponsor = message->job_list.next; sponsor; sponsor = sponsor->message_peers.next) {
-       if (sponsor->rcpt_count >= sponsor->rcpt_limit || sponsor == job)
-           continue;
-       if (sponsor->stack_level < 0 || message->rcpt_offset == 0)
-           qmgr_job_move_limits(sponsor);
-    }
-    if (message->rcpt_offset == 0) {
-       qmgr_job_move_limits(job);
-    }
-
-    /*
-     * When there are no more entries for this peer, discard the peer
-     * structure.
-     */
-    peer->refcount--;
-    if (peer->refcount == 0)
-       qmgr_peer_free(peer);
-
-    /*
-     * When the in-core queue for this site is empty and when this site is
-     * not dead, discard the in-core queue. When this site is dead, but the
-     * number of in-core queues exceeds some threshold, get rid of this
-     * in-core queue anyway, in order to avoid running out of memory.
-     */
-    if (queue->todo.next == 0 && queue->busy.next == 0) {
-       if (queue->window == 0 && qmgr_queue_count > 2 * var_qmgr_rcpt_limit)
-           qmgr_queue_unthrottle(queue);
-       if (queue->window > 0)
-           qmgr_queue_done(queue);
-    }
-
-    /*
-     * Update the in-core message reference count. When the in-core message
-     * structure has no more references, dispose of the message.
-     */
-    message->refcount--;
-    if (message->refcount == 0)
-       qmgr_active_done(message);
-}
-
-/* qmgr_entry_create - create queue todo entry */
-
-QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message)
-{
-    QMGR_ENTRY *entry;
-    QMGR_QUEUE *queue = peer->queue;
-
-    /*
-     * Sanity check.
-     */
-    if (queue->window == 0)
-       msg_panic("qmgr_entry_create: dead queue: %s", queue->name);
-
-    entry = (QMGR_ENTRY *) mymalloc(sizeof(QMGR_ENTRY));
-    entry->stream = 0;
-    entry->message = message;
-    qmgr_rcpt_list_init(&entry->rcpt_list);
-    message->refcount++;
-    entry->peer = peer;
-    QMGR_LIST_APPEND(peer->entry_list, entry, peer_peers);
-    peer->refcount++;
-    entry->queue = queue;
-    QMGR_LIST_APPEND(queue->todo, entry, queue_peers);
-    queue->todo_refcount++;
-    return (entry);
-}
diff --git a/postfix/src/nqmgr/qmgr_job.c b/postfix/src/nqmgr/qmgr_job.c
deleted file mode 100644 (file)
index 3be9309..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_job 3
-/* SUMMARY
-/*     per-transport jobs
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_JOB *qmgr_job_obtain(message, transport)
-/*     QMGR_MESSAGE *message;
-/*     QMGR_TRANSPORT *transport;
-/*
-/*     void qmgr_job_free(job)
-/*     QMGR_JOB *job;
-/*
-/*     void qmgr_job_move_limits(job)
-/*     QMGR_JOB *job;
-/*
-/*     QMGR_ENTRY *qmgr_job_entry_select(transport)
-/*     QMGR_TRANSPORT *transport;
-/* DESCRIPTION
-/*     These routines add/delete/manipulate per-transport jobs.
-/*     Each job corresponds to a specific transport and message.
-/*     Each job has a peer list containing all pending delivery
-/*     requests for that message.
-/*
-/*     qmgr_job_obtain() finds an existing job for named message and
-/*     transport combination. New empty job is created if no existing can
-/*     be found. In either case, the job is prepared for assignement of
-/*     (more) message recipients.
-/*
-/*     qmgr_job_free() disposes of a per-transport job after all
-/*     its entries have been taken care of. It is an error to dispose
-/*     of a job that is still in use.
-/*
-/*     qmgr_job_entry_select() attempts to find the next entry suitable
-/*     for delivery. The job preempting algorithm is also exercised.
-/*     If necessary, an attempt to read more recipients into core is made.
-/*     This can result in creation of more job, queue and entry structures.
-/*
-/*     qmgr_job_move_limits() takes care of proper distribution of the
-/*     per-transport recipients limit among the per-transport jobs.
-/*     Should be called whenever a job's recipient slot becomes available.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure.
-/* LICENSE
-/* .ad
-/* .fi
-/*     The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/*     Patrik Rak
-/*     patrik@raxoft.cz
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <events.h>
-#include <htable.h>
-#include <mymalloc.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* Forward declarations */
-
-static void qmgr_job_pop(QMGR_JOB *);
-
-/* Helper macros */
-
-#define HAS_ENTRIES(job) ((job)->selected_entries < (job)->read_entries)
-
-/*
- * The MIN_ENTRIES macro may underestimate a lot but we can't use message->rcpt_unread
- * because we don't know if all those unread recipients go to our transport yet.
- */
-
-#define MIN_ENTRIES(job) ((job)->read_entries)
-#define MAX_ENTRIES(job) ((job)->read_entries + (job)->message->rcpt_unread)
-
-#define RESET_CANDIDATE_CACHE(transport) do { \
-                                            (transport)->candidate_cache_time = (time_t) 0; \
-                                            (transport)->candidate_cache = 0; \
-                                        } while(0)
-
-/* qmgr_job_create - create and initialize message job structure */
-
-static QMGR_JOB *qmgr_job_create(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
-{
-    QMGR_JOB *job;
-
-    job = (QMGR_JOB *) mymalloc(sizeof(QMGR_JOB));
-    job->message = message;
-    QMGR_LIST_APPEND(message->job_list, job, message_peers);
-    htable_enter(transport->job_byname, message->queue_id, (char *) job);
-    job->transport = transport;
-    QMGR_LIST_INIT(job->transport_peers);
-    job->peer_byname = htable_create(0);
-    QMGR_LIST_INIT(job->peer_list);
-    job->stack_level = 0;
-    job->slots_used = 0;
-    job->slots_available = 0;
-    job->selected_entries = 0;
-    job->read_entries = 0;
-    job->rcpt_count = 0;
-    job->rcpt_limit = 0;
-    return (job);
-}
-
-/* qmgr_job_link - append the job to the job list, according to the time it was queued */
-
-static void qmgr_job_link(QMGR_JOB *job)
-{
-    QMGR_TRANSPORT *transport = job->transport;
-    QMGR_MESSAGE *message = job->message;
-    QMGR_JOB *prev,
-           *next,
-           *unread;
-    int     delay;
-
-    unread = transport->job_next_unread;
-
-    /*
-     * This may look inefficient but under normal operation it is expected
-     * that the loop will stop right away, resulting in normal list append
-     * below. However, this code is necessary for reviving retired jobs and
-     * for jobs which are created long after the first chunk of recipients
-     * was read in-core (either of these can happen only for multi-transport
-     * messages).
-     * 
-     * In case this is found unsatisfactory one day, it's possible to deploy
-     * some smarter technique (using some form of lookup trees perhaps).
-     */
-    for (next = 0, prev = transport->job_list.prev; prev;
-        next = prev, prev = prev->transport_peers.prev) {
-       delay = message->queued_time - prev->message->queued_time;
-       if (delay >= 0)
-           break;
-       if (unread == prev)
-           unread = 0;
-    }
-
-    /*
-     * Don't link the new job in front of the first job on the job list if
-     * that job was already used for the regular delivery. This seems like a
-     * subtle difference but it helps many invariants used at various other
-     * places to remain true.
-     */
-    if (prev == 0 && next != 0 && next->slots_used != 0) {
-       prev = next;
-       next = next->transport_peers.next;
-
-       /*
-        * The following is not currently necessary but is done anyway for
-        * the sake of consistency.
-        */
-       if (prev == transport->job_next_unread)
-           unread = prev;
-    }
-
-    /*
-     * Link the job into the proper place on the job list.
-     */
-    job->transport_peers.prev = prev;
-    job->transport_peers.next = next;
-    if (prev != 0)
-       prev->transport_peers.next = job;
-    else
-       transport->job_list.next = job;
-    if (next != 0)
-       next->transport_peers.prev = job;
-    else
-       transport->job_list.prev = job;
-
-    /*
-     * Update the pointer to the first unread job on the job list and steal
-     * the unused recipient slots from the old one.
-     */
-    if (unread == 0) {
-       unread = transport->job_next_unread;
-       transport->job_next_unread = job;
-       if (unread != 0)
-           qmgr_job_move_limits(unread);
-    }
-
-    /*
-     * Get as much recipient slots as possible. The excess will be returned
-     * to the transport pool as soon as the exact amount required is known
-     * (which is usually after all recipients have been read in core).
-     */
-    if (transport->rcpt_unused > 0) {
-       job->rcpt_limit += transport->rcpt_unused;
-       message->rcpt_limit += transport->rcpt_unused;
-       transport->rcpt_unused = 0;
-    }
-}
-
-/* qmgr_job_find - lookup job associated with named message and transport */
-
-static QMGR_JOB *qmgr_job_find(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
-{
-
-    /*
-     * Instead of traversing the message job list, we use single per
-     * transport hash table. This is better (at least with respect to memory
-     * usage) than having single hash table (usually almost empty) for each
-     * message.
-     */
-    return ((QMGR_JOB *) htable_find(transport->job_byname, message->queue_id));
-}
-
-/* qmgr_job_obtain - find/create the appropriate job and make it ready for new recipients */
-
-QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport)
-{
-    QMGR_JOB *job;
-
-    /*
-     * Try finding an existing job and revive it if it was already retired.
-     * Create a new job for this transport/message combination otherwise.
-     */
-    if ((job = qmgr_job_find(message, transport)) != 0) {
-       if (job->stack_level < 0) {
-           job->stack_level = 0;
-           qmgr_job_link(job);
-       }
-    } else {
-       job = qmgr_job_create(message, transport);
-       qmgr_job_link(job);
-    }
-
-    /*
-     * Reset the candidate cache because of the new expected recipients.
-     */
-    RESET_CANDIDATE_CACHE(transport);
-
-    return (job);
-}
-
-/* qmgr_job_move_limits - move unused recipient slots to the next job */
-
-void    qmgr_job_move_limits(QMGR_JOB *job)
-{
-    QMGR_TRANSPORT *transport = job->transport;
-    QMGR_MESSAGE *message = job->message;
-    QMGR_JOB *next = transport->job_next_unread;
-    int     rcpt_unused,
-            msg_rcpt_unused;
-
-    /*
-     * Find next unread job on the job list if necessary. Cache it for later.
-     * This makes the amortized efficiency of this routine O(1) per job.
-     */
-    if (job == next) {
-       for (next = next->transport_peers.next; next; next = next->transport_peers.next)
-           if (next->message->rcpt_offset != 0)
-               break;
-       transport->job_next_unread = next;
-    }
-
-    /*
-     * Calculate the number of available unused slots.
-     */
-    rcpt_unused = job->rcpt_limit - job->rcpt_count;
-    msg_rcpt_unused = message->rcpt_limit - message->rcpt_count;
-    if (msg_rcpt_unused < rcpt_unused)
-       rcpt_unused = msg_rcpt_unused;
-
-    /*
-     * Transfer the unused recipient slots back to the transport pool and to
-     * the next not-fully-read job. Job's message limits are adjusted
-     * accordingly.
-     */
-    if (rcpt_unused > 0) {
-       job->rcpt_limit -= rcpt_unused;
-       message->rcpt_limit -= rcpt_unused;
-       transport->rcpt_unused += rcpt_unused;
-       if (next != 0 && (rcpt_unused = transport->rcpt_unused) > 0) {
-           next->rcpt_limit += rcpt_unused;
-           next->message->rcpt_limit += rcpt_unused;
-           transport->rcpt_unused = 0;
-       }
-    }
-}
-
-/* qmgr_job_retire - remove the job from the job list while waiting for recipients to deliver */
-
-static void qmgr_job_retire(QMGR_JOB *job)
-{
-    char   *myname = "qmgr_job_retire";
-    QMGR_TRANSPORT *transport = job->transport;
-
-    if (msg_verbose)
-       msg_info("%s: %s", myname, job->message->queue_id);
-
-    /*
-     * Sanity checks.
-     */
-    if (job->stack_level != 0)
-       msg_panic("%s: non-zero stack level (%d)", myname, job->stack_level);
-
-    /*
-     * Make sure this job is not cached as the next unread job for this
-     * transport. The qmgr_entry_done() will make sure that the slots donated
-     * by this job are moved back to the transport pool as soon as possible.
-     */
-    qmgr_job_move_limits(job);
-
-    /*
-     * Invalidate the candidate selection cache if necessary.
-     */
-    if (job == transport->candidate_cache
-     || (transport->job_stack.next == 0 && job == transport->job_list.next))
-       RESET_CANDIDATE_CACHE(transport);
-
-    /*
-     * Remove the job from the job list and mark it as retired.
-     */
-    QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers);
-    job->stack_level = -1;
-}
-
-/* qmgr_job_free - release the job structure */
-
-void    qmgr_job_free(QMGR_JOB *job)
-{
-    char   *myname = "qmgr_job_free";
-    QMGR_MESSAGE *message = job->message;
-    QMGR_TRANSPORT *transport = job->transport;
-
-    if (msg_verbose)
-       msg_info("%s: %s %s", myname, message->queue_id, transport->name);
-
-    /*
-     * Sanity checks.
-     */
-    if (job->rcpt_count)
-       msg_panic("%s: non-zero recipient count (%d)", myname, job->rcpt_count);
-
-    /*
-     * Remove the job from the job stack if necessary.
-     */
-    if (job->stack_level > 0)
-       qmgr_job_pop(job);
-
-    /*
-     * Return any remaining recipient slots back to the recipient slots pool.
-     */
-    qmgr_job_move_limits(job);
-    if (job->rcpt_limit)
-       msg_panic("%s: recipient slots leak (%d)", myname, job->rcpt_limit);
-
-    /*
-     * Invalidate the candidate selection cache if necessary.
-     */
-    if (job == transport->candidate_cache
-     || (transport->job_stack.next == 0 && job == transport->job_list.next))
-       RESET_CANDIDATE_CACHE(transport);
-
-    /*
-     * Unlink and discard the structure. Check if the job is still on the
-     * transport job list or if it was already retired before unlinking it.
-     */
-    if (job->stack_level >= 0)
-       QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers);
-    QMGR_LIST_UNLINK(message->job_list, QMGR_JOB *, job, message_peers);
-    htable_delete(transport->job_byname, message->queue_id, (void (*) (char *)) 0);
-    htable_free(job->peer_byname, (void (*) (char *)) 0);
-    myfree((char *) job);
-}
-
-/* qmgr_job_count_slots - maintain the delivery slot counters */
-
-static void qmgr_job_count_slots(QMGR_JOB *current, QMGR_JOB *job)
-{
-
-    /*
-     * Count the number of delivery slots used during the delivery of the
-     * selected job. Also count the number of delivery slots available for
-     * preemption.
-     * 
-     * However, suppress any slot counting if we didn't start regular delivery
-     * of the selected job yet.
-     */
-    if (job == current || job->slots_used > 0) {
-       job->slots_used++;
-       job->slots_available++;
-    }
-
-    /*
-     * If the selected job is not the current job, its chance to be chosen by
-     * qmgr_job_candidate() has slightly changed. If we would like to make
-     * the candidate cache completely transparent, we should invalidate it
-     * now.
-     * 
-     * However, this case should usually happen only at "end of current job"
-     * phase, when it's unlikely that the current job can be preempted
-     * anyway.  And because it's likely to happen quite often then, we
-     * intentionally don't reset the cache, to safe some cycles. Furthermore,
-     * the cache times out every second anyway.
-     */
-#if 0
-    if (job != current)
-       RESET_CANDIDATE_CACHE(job->transport);
-#endif
-}
-
-/* qmgr_job_candidate - find best job candidate for preempting given job */
-
-static QMGR_JOB *qmgr_job_candidate(QMGR_JOB *current)
-{
-    QMGR_TRANSPORT *transport = current->transport;
-    QMGR_JOB *job,
-           *best_job = 0;
-    float   score,
-            best_score = 0.0;
-    int     max_slots,
-            max_needed_entries,
-            max_total_entries;
-    int     delay;
-    time_t  now = event_time();
-
-    /*
-     * Fetch the result directly from the cache if the cache is still valid.
-     * 
-     * Note that we cache negative results too, so the cache must be invalidated
-     * by resetting the cache time, not the candidate pointer itself.
-     */
-    if (transport->candidate_cache_time == now)
-       return (transport->candidate_cache);
-
-    /*
-     * Estimate the minimum amount of delivery slots that can ever be
-     * accumulated for the given job. All jobs that won't fit into these
-     * slots are excluded from the candidate selection.
-     */
-    max_slots = (MIN_ENTRIES(current) - current->selected_entries
-                + current->slots_available) / transport->slot_cost;
-
-    /*
-     * Select the candidate with best time_since_queued/total_recipients
-     * score. In addition to jobs which don't meet the max_slots limit, skip
-     * also jobs which don't have any selectable entries at the moment.
-     * 
-     * By the way, the selection is reasonably resistant to OS time warping,
-     * too.
-     * 
-     * However, don't bother searching if we can't find anything suitable
-     * anyway.
-     */
-    if (max_slots > 0) {
-       for (job = transport->job_list.next; job; job = job->transport_peers.next) {
-           if (job->stack_level != 0 || job == current)
-               continue;
-           max_total_entries = MAX_ENTRIES(job);
-           max_needed_entries = max_total_entries - job->selected_entries;
-           delay = now - job->message->queued_time + 1;
-           if (max_needed_entries > 0 && max_needed_entries <= max_slots) {
-               score = (float) delay / max_total_entries;
-               if (score > best_score) {
-                   best_score = score;
-                   best_job = job;
-               }
-           }
-
-           /*
-            * Stop early if the best score is as good as it can get.
-            */
-           if (delay <= best_score)
-               break;
-       }
-    }
-
-    /*
-     * Cache the result for later use.
-     */
-    transport->candidate_cache = best_job;
-    transport->candidate_cache_time = now;
-
-    return (best_job);
-}
-
-/* qmgr_job_preempt - preempt large message with smaller one */
-
-static QMGR_JOB *qmgr_job_preempt(QMGR_JOB *current)
-{
-    char   *myname = "qmgr_job_preempt";
-    QMGR_TRANSPORT *transport = current->transport;
-    QMGR_JOB *job;
-    int     rcpt_slots;
-
-    /*
-     * Suppress preempting completely if the current job is not big enough to
-     * accumulate even the mimimal number of slots required.
-     * 
-     * Also, don't look for better job candidate if there are no available slots
-     * yet (the count can get negative due to the slot loans below).
-     */
-    if (current->slots_available <= 0
-      || MAX_ENTRIES(current) < transport->min_slots * transport->slot_cost)
-       return (current);
-
-    /*
-     * Find best candidate for preempting the current job.
-     * 
-     * Note that the function also takes care that the candidate fits within the
-     * number of delivery slots which the current job is still able to
-     * accumulate.
-     */
-    if ((job = qmgr_job_candidate(current)) == 0)
-       return (current);
-
-    /*
-     * Sanity checks.
-     */
-    if (job == current)
-       msg_panic("%s: attempt to preempt itself", myname);
-    if (job->stack_level != 0)
-       msg_panic("%s: already on the job stack (%d)", myname, job->stack_level);
-
-    /*
-     * Check if there is enough available delivery slots accumulated to
-     * preempt the current job.
-     * 
-     * The slot loaning scheme improves the average message response time. Note
-     * that the loan only allows the preemption happen earlier, though. It
-     * doesn't affect how many slots have to be "paid" - the full number of
-     * slots required has to be accumulated later before next preemption on
-     * the same stack level can happen in either case.
-     */
-    if (current->slots_available / transport->slot_cost
-       + transport->slot_loan
-       < (MAX_ENTRIES(job) - job->selected_entries)
-       * transport->slot_loan_factor / 100.0)
-       return (current);
-
-    /*
-     * Preempt the current job.
-     */
-    QMGR_LIST_PREPEND(transport->job_stack, job, stack_peers);
-    job->stack_level = current->stack_level + 1;
-
-    /*
-     * Add part of extra recipient slots reserved for preempting jobs to the
-     * new current job if necessary.
-     * 
-     * Note that transport->rcpt_unused is within <-rcpt_per_stack,0> in such
-     * case.
-     */
-    if (job->message->rcpt_offset != 0) {
-       rcpt_slots = (transport->rcpt_per_stack + transport->rcpt_unused + 1) / 2;
-       job->rcpt_limit += rcpt_slots;
-       job->message->rcpt_limit += rcpt_slots;
-       transport->rcpt_unused -= rcpt_slots;
-    }
-
-    /*
-     * Candidate cache must be reset because the current job has changed
-     * completely.
-     */
-    RESET_CANDIDATE_CACHE(transport);
-
-    if (msg_verbose)
-       msg_info("%s: %s by %s", myname, current->message->queue_id,
-                job->message->queue_id);
-
-    return (job);
-}
-
-/* qmgr_job_pop - remove the job from the job preemption stack */
-
-static void qmgr_job_pop(QMGR_JOB *job)
-{
-    QMGR_TRANSPORT *transport = job->transport;
-    QMGR_JOB *parent;
-
-    if (msg_verbose)
-       msg_info("qmgr_job_pop: %s", job->message->queue_id);
-
-    /*
-     * Adjust the number of delivery slots available to preempt job's parent.
-     * 
-     * Note that we intentionally do not adjust slots_used of the parent. Doing
-     * so would decrease the maximum per message inflation factor if the
-     * preemption appeared near the end of parent delivery.
-     * 
-     * For the same reason we do not adjust parent's slots_available if the
-     * parent is not the original parent preempted by the selected job (i.e.,
-     * the original parent job has already completed).
-     * 
-     * The special case when the head of the job list was preempted and then
-     * delivered before the preempting job itself is taken care of too.
-     * Otherwise we would decrease available slot counter of some job that
-     * was not in fact preempted yet.
-     */
-    if (((parent = job->stack_peers.next) != 0
-    || ((parent = transport->job_list.next) != 0 && parent->slots_used > 0))
-       && job->stack_level == parent->stack_level + 1)
-       parent->slots_available -= job->slots_used * transport->slot_cost;
-
-    /*
-     * Invalidate the candidate selection cache if necessary.
-     */
-    if (job == transport->job_stack.next)
-       RESET_CANDIDATE_CACHE(transport);
-
-    /*
-     * Remove the job from the job stack and reinitialize the slot counters.
-     */
-    QMGR_LIST_UNLINK(transport->job_stack, QMGR_JOB *, job, stack_peers);
-    job->stack_level = 0;
-    job->slots_used = 0;
-    job->slots_available = 0;
-}
-
-/* qmgr_job_peer_select - select next peer suitable for delivery */
-
-static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB *job)
-{
-    QMGR_PEER *peer;
-    QMGR_MESSAGE *message = job->message;
-
-    if (HAS_ENTRIES(job) && (peer = qmgr_peer_select(job)) != 0)
-       return (peer);
-
-    /*
-     * Try reading in more recipients. Note that we do not try to read them
-     * as soon as possible as that would decrease the chance of per-site
-     * recipient grouping. We waited until reading more is really necessary.
-     */
-    if (message->rcpt_offset != 0 && message->rcpt_limit > message->rcpt_count) {
-       qmgr_message_realloc(message);
-       if (HAS_ENTRIES(job))
-           return (qmgr_peer_select(job));
-    }
-    return (0);
-}
-
-/* qmgr_job_entry_select - select next entry suitable for delivery */
-
-QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *transport)
-{
-    QMGR_JOB *job,
-           *current,
-           *next;
-    QMGR_PEER *peer;
-    QMGR_ENTRY *entry;
-
-    /*
-     * Select the "current" job.
-     */
-    if ((current = transport->job_stack.next) == 0
-       && (current = transport->job_list.next) == 0)
-       return (0);
-
-    /*
-     * Exercise the preempting algorithm if enabled.
-     * 
-     * The slot_cost equal to 1 causes the algorithm to degenerate and is
-     * therefore disabled too.
-     */
-    if (transport->slot_cost >= 2)
-       current = qmgr_job_preempt(current);
-
-    /*
-     * Select next entry suitable for delivery. First check the stack of
-     * preempting jobs, then the list of all remaining jobs in FIFO order.
-     * 
-     * Note that although the loops may look inefficient, they only serve as a
-     * recovery mechanism when an entry of the current job itself can't be
-     * selected due peer concurrency restrictions. In most cases some entry
-     * of the current job itself is selected.
-     * 
-     * Note that both loops also take care of getting the "stall" current job
-     * (job with no entries currently available) out of the way if necessary.
-     * Stall jobs can appear in case of multi-transport messages whose
-     * recipients don't fit in-core at once. Some jobs created by such
-     * message may have only few recipients and would block the job queue
-     * until all other jobs of the message are delivered. Trying to read in
-     * more recipients of such jobs each selection would also break the per
-     * peer recipient grouping of the other jobs. That's why we retire such
-     * jobs below.
-     */
-    for (job = transport->job_stack.next; job; job = next) {
-       next = job->stack_peers.next;
-       if ((peer = qmgr_job_peer_select(job)) != 0) {
-           entry = qmgr_entry_select(peer);
-           qmgr_job_count_slots(current, job);
-
-           /*
-            * In case we selected the very last job entry, remove the job
-            * from the job stack and the job list right now.
-            * 
-            * This action uses the assumption that once the job entry has been
-            * selected, it can be unselected only before the message ifself
-            * is deferred. Thus the job with all entries selected can't
-            * re-appear with more entries available for selection again
-            * (without reading in more entries from the queue file, which in
-            * turn invokes qmgr_job_obtain() which re-links the job back on
-            * the list if necessary).
-            * 
-            * Note that qmgr_job_move_limits() transfers the recipients slots
-            * correctly even if the job is unlinked from the job list thanks
-            * to the job_next_unread caching.
-            */
-           if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0) {
-               qmgr_job_pop(job);
-               qmgr_job_retire(job);
-           }
-           return (entry);
-       } else if (job == current && !HAS_ENTRIES(job)) {
-           qmgr_job_pop(job);
-           qmgr_job_retire(job);
-           current = next ? next : transport->job_list.next;
-       }
-    }
-
-    /*
-     * Try the regular job list if there is nothing (suitable) on the job
-     * stack.
-     */
-    for (job = transport->job_list.next; job; job = next) {
-       next = job->transport_peers.next;
-       if (job->stack_level != 0)
-           continue;
-       if ((peer = qmgr_job_peer_select(job)) != 0) {
-           entry = qmgr_entry_select(peer);
-           qmgr_job_count_slots(current, job);
-
-           /*
-            * In case we selected the very last job entry, remove the job
-            * from the job list right away.
-            */
-           if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0)
-               qmgr_job_retire(job);
-           return (entry);
-       } else if (job == current && !HAS_ENTRIES(job)) {
-           qmgr_job_retire(job);
-           current = next;
-       }
-    }
-    return (0);
-}
diff --git a/postfix/src/nqmgr/qmgr_message.c b/postfix/src/nqmgr/qmgr_message.c
deleted file mode 100644 (file)
index 722f44a..0000000
+++ /dev/null
@@ -1,961 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_message 3
-/* SUMMARY
-/*     in-core message structures
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     int     qmgr_message_count;
-/*     int     qmgr_recipient_count;
-/*
-/*     QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags)
-/*     const char *class;
-/*     const char *name;
-/*     int     qflags;
-/*
-/*     QMGR_MESSAGE *qmgr_message_realloc(message)
-/*     QMGR_MESSAGE *message;
-/*
-/*     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.
-/*
-/*     qmgr_message_count is a global counter for the total number
-/*     of in-core message structures (i.e. the total size of the
-/*     `active' message queue).
-/*
-/*     qmgr_recipient_count is a global counter for the total number
-/*     of in-core recipient structures (i.e. the sum of all recipients
-/*     in all in-core message structures).
-/*
-/*     qmgr_message_alloc() creates an in-core message structure
-/*     with sender and recipient information taken from the named queue
-/*     file. A null result means the queue file could not be read or
-/*     that the queue file contained incorrect information. A result
-/*     QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
-/*     of recipients read from a queue file is limited by the global
-/*     var_qmgr_rcpt_limit configuration parameter. When the limit
-/*     is reached, the \fIrcpt_offset\fR structure member is set to
-/*     the position where the read was terminated. Recipients are
-/*     run through the resolver, and are assigned to destination
-/*     queues. Recipients that cannot be assigned are deferred or
-/*     bounced. Mail that has bounced twice is silently absorbed.
-/*
-/*     qmgr_message_realloc() resumes reading recipients from the queue
-/*     file, and updates the recipient list and \fIrcpt_offset\fR message
-/*     structure members. A null result means that the file could not be
-/*     read or that the file contained incorrect information. Recipient
-/*     limit imposed this time is based on the position of the message
-/*     job(s) on corresponding transport job list(s). It's considered
-/*     an error to call this when the recipient slots can't be allocated.
-/*
-/*     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
-/*     envelope(3) message envelope parser
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <stdio.h>                     /* sscanf() */
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <events.h>
-#include <mymalloc.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <split_at.h>
-#include <valid_hostname.h>
-#include <argv.h>
-#include <stringops.h>
-#include <myflock.h>
-
-/* Global library. */
-
-#include <dict.h>
-#include <mail_queue.h>
-#include <mail_params.h>
-#include <canon_addr.h>
-#include <record.h>
-#include <rec_type.h>
-#include <sent.h>
-#include <deliver_completed.h>
-#include <mail_addr_find.h>
-#include <opened.h>
-#include <resolve_local.h>
-
-/* Client stubs. */
-
-#include <resolve_clnt.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-int     qmgr_message_count;
-int     qmgr_recipient_count;
-
-/* qmgr_message_create - create in-core message structure */
-
-static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
-                                          const char *queue_id, int qflags)
-{
-    QMGR_MESSAGE *message;
-
-    message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE));
-    qmgr_message_count++;
-    message->flags = 0;
-    message->qflags = qflags;
-    message->fp = 0;
-    message->refcount = 0;
-    message->single_rcpt = 0;
-    message->arrival_time = 0;
-    message->queued_time = event_time();
-    message->data_offset = 0;
-    message->queue_id = mystrdup(queue_id);
-    message->queue_name = mystrdup(queue_name);
-    message->sender = 0;
-    message->errors_to = 0;
-    message->return_receipt = 0;
-    message->filter_xport = 0;
-    message->inspect_xport = 0;
-    message->data_size = 0;
-    message->warn_offset = 0;
-    message->warn_time = 0;
-    message->rcpt_offset = 0;
-    message->unread_offset = 0;
-    qmgr_rcpt_list_init(&message->rcpt_list);
-    message->rcpt_count = 0;
-    message->rcpt_limit = var_qmgr_msg_rcpt_limit;
-    message->rcpt_unread = 0;
-    QMGR_LIST_INIT(message->job_list);
-    return (message);
-}
-
-/* qmgr_message_close - close queue file */
-
-static void qmgr_message_close(QMGR_MESSAGE *message)
-{
-    vstream_fclose(message->fp);
-    message->fp = 0;
-}
-
-/* qmgr_message_open - open queue file */
-
-static int qmgr_message_open(QMGR_MESSAGE *message)
-{
-
-    /*
-     * Sanity check.
-     */
-    if (message->fp)
-       msg_panic("%s: queue file is open", message->queue_id);
-
-    /*
-     * Open this queue file. Skip files that we cannot open. Back off when
-     * the system appears to be running out of resources.
-     */
-    if ((message->fp = mail_queue_open(message->queue_name,
-                                      message->queue_id,
-                                      O_RDWR, 0)) == 0) {
-       if (errno != ENOENT)
-           msg_fatal("open %s %s: %m", message->queue_name, message->queue_id);
-       msg_warn("open %s %s: %m", message->queue_name, message->queue_id);
-       return (-1);
-    }
-    return (0);
-}
-
-/* qmgr_message_oldstyle_scan - extract required information from an old style queue file */
-
-static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
-{
-    VSTRING *buf;
-    long    orig_offset,
-            curr_offset,
-            extra_offset;
-    int     rec_type;
-    char   *start;
-
-    /*
-     * Initialize. No early returns or we have a memory leak.
-     */
-    buf = vstring_alloc(100);
-    if ((orig_offset = vstream_ftell(message->fp)) < 0)
-       msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
-
-    /*
-     * Rewind to the very beginning to make sure we see all records.
-     */
-    if (vstream_fseek(message->fp, 0, SEEK_SET) < 0)
-       msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-
-    /*
-     * Scan through the old style queue file. Count the total number of
-     * recipients and find the data/extra sections offsets. Note that the new
-     * queue files require that data_size equals extra_offset - data_offset,
-     * so we set data_size to this as well and ignore the size record itself
-     * completely.
-     */
-    message->rcpt_unread = 0;
-    do {
-       if ((curr_offset = vstream_ftell(message->fp)) < 0)
-           msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
-       rec_type = rec_get(message->fp, buf, 0);
-       start = vstring_str(buf);
-       if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_RCPT) {
-           message->rcpt_unread++;
-       } else if (rec_type == REC_TYPE_MESG) {
-           if ((message->data_offset = vstream_ftell(message->fp)) < 0)
-               msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
-           if ((extra_offset = atol(start)) <= curr_offset)
-               msg_fatal("bad extra offset %s file %s",
-                         start, VSTREAM_PATH(message->fp));
-           if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
-               msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-           message->data_size = extra_offset - message->data_offset;
-       }
-    } while (rec_type > 0 && rec_type != REC_TYPE_END);
-
-    /*
-     * Clean up.
-     */
-    if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0)
-       msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-    vstring_free(buf);
-
-    /*
-     * Sanity checks. Verify that all required information was found,
-     * including the queue file end marker.
-     */
-    if (message->data_offset == 0 || rec_type != REC_TYPE_END)
-       msg_fatal("%s: envelope records out of order", message->queue_id);
-}
-
-/* qmgr_message_read - read envelope records */
-
-static int qmgr_message_read(QMGR_MESSAGE *message)
-{
-    VSTRING *buf;
-    long    extra_offset;
-    int     rec_type;
-    long    curr_offset;
-    long    save_offset = message->rcpt_offset;        /* save a flag */
-    char   *start;
-    int     recipient_limit;
-
-    /*
-     * Initialize. No early returns or we have a memory leak.
-     */
-    buf = vstring_alloc(100);
-
-    /*
-     * If we re-open this file, skip over on-file recipient records that we
-     * already looked at, and refill the in-core recipient address list.
-     * 
-     * For the first time, the message recipient limit is calculated from the
-     * global recipient limit. This is to avoid reading little recipients
-     * when the active queue is near empty. When the queue becomes full, only
-     * the necessary amount is read in core. Such priming is necessary
-     * because there are no message jobs yet.
-     * 
-     * For the next time, the recipient limit is based solely on the message
-     * jobs' positions in the job lists and/or job stacks.
-     */
-    if (message->rcpt_offset) {
-       if (message->rcpt_list.len)
-           msg_panic("%s: recipient list not empty on recipient reload", message->queue_id);
-       if (message->rcpt_limit <= message->rcpt_count)
-           msg_panic("%s: no recipient slots available", message->queue_id);
-       if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0)
-           msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-       message->rcpt_offset = 0;
-       recipient_limit = message->rcpt_limit - message->rcpt_count;
-    } else {
-       recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count;
-       if (recipient_limit < message->rcpt_limit)
-           recipient_limit = message->rcpt_limit;
-    }
-    if (recipient_limit <= 0)
-       msg_panic("%s: no recipient slots available", message->queue_id);
-
-    /*
-     * Read envelope records. XXX Rely on the front-end programs to enforce
-     * record size limits. Read up to recipient_limit recipients from the
-     * queue file, to protect against memory exhaustion. Recipient records
-     * may appear before or after the message content, so we keep reading
-     * from the queue file until we have enough recipients (rcpt_offset != 0)
-     * and until we know where the message content starts (data_offset != 0).
-     * 
-     * Note that the total recipient count record is accurate only for fresh
-     * queue files. After some of the recipients are marked as done and the
-     * queue file is deferred, it can be used as upper bound estimate only.
-     * Fortunately, this poses no major problem on the scheduling algorithm,
-     * as the only impact is that the already deferred messages are not
-     * chosen by qmgr_job_candidate() as often as they could.
-     */
-    do {
-       if ((curr_offset = vstream_ftell(message->fp)) < 0)
-           msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
-       if (curr_offset == message->data_offset && curr_offset > 0) {
-           extra_offset = curr_offset + message->data_size;
-           if (extra_offset <= curr_offset)
-               msg_fatal("bad extra offset %ld file %s",
-                         extra_offset, VSTREAM_PATH(message->fp));
-           if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
-               msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
-           curr_offset = extra_offset;
-       }
-       rec_type = rec_get(message->fp, buf, 0);
-       start = vstring_str(buf);
-       if (rec_type == REC_TYPE_SIZE) {
-           if (message->data_size == 0) {
-               switch (sscanf(start, "%ld %ld %d", &message->data_size,
-                           &message->data_offset, &message->rcpt_unread)) {
-               case 1:
-
-                   /*
-                    * Gather data_size, data_offset and rcpt_unread values
-                    * from the old style queue file.
-                    */
-                   qmgr_message_oldstyle_scan(message);
-                   break;
-               case 3:
-
-                   /*
-                    * No extra work for new style queue files.
-                    */
-                   break;
-               default:
-                   msg_fatal("%s: weird size record", message->queue_id);
-                   break;
-               }
-           }
-       } else if (rec_type == REC_TYPE_TIME) {
-           if (message->arrival_time == 0)
-               message->arrival_time = atol(start);
-       } else if (rec_type == REC_TYPE_FILT) {
-           if (message->filter_xport == 0)
-               message->filter_xport = mystrdup(start);
-       } else if (rec_type == REC_TYPE_INSP) {
-           if (message->inspect_xport == 0)
-               message->inspect_xport = mystrdup(start);
-       } else if (rec_type == REC_TYPE_FROM) {
-           if (message->sender == 0) {
-               message->sender = mystrdup(start);
-               opened(message->queue_id, message->sender,
-                      message->data_size, message->rcpt_unread,
-                      "queue %s", message->queue_name);
-           }
-       } else if (rec_type == REC_TYPE_DONE) {
-           if (curr_offset > message->unread_offset) {
-               message->unread_offset = curr_offset;
-               message->rcpt_unread--;
-           }
-       } else if (rec_type == REC_TYPE_RCPT) {
-           if (message->rcpt_list.len < recipient_limit) {
-               message->rcpt_unread--;
-               qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
-               if (message->rcpt_list.len >= recipient_limit) {
-                   if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
-                       msg_fatal("vstream_ftell %s: %m",
-                                 VSTREAM_PATH(message->fp));
-                   if (message->data_offset != 0
-                       && message->errors_to != 0
-                       && message->return_receipt != 0)
-                       break;
-               }
-           }
-       } else if (rec_type == REC_TYPE_ERTO) {
-           if (message->errors_to == 0) {
-               message->errors_to = mystrdup(start);
-               if (message->data_offset != 0
-                   && message->rcpt_offset != 0
-                   && message->return_receipt != 0)
-                   break;
-           }
-       } else if (rec_type == REC_TYPE_RRTO) {
-           if (message->return_receipt == 0) {
-               message->return_receipt = mystrdup(start);
-               if (message->data_offset != 0
-                   && message->rcpt_offset != 0
-                   && message->errors_to != 0)
-                   break;
-           }
-       } 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);
-
-    /*
-     * Avoid clumsiness elsewhere in the program. When sending data across an
-     * IPC channel, sending an empty string is more convenient than sending a
-     * null pointer.
-     */
-    if (message->errors_to == 0)
-       message->errors_to = mystrdup("");
-    if (message->return_receipt == 0)
-       message->return_receipt = mystrdup("");
-
-    /*
-     * Clean up.
-     */
-    vstring_free(buf);
-
-    /*
-     * Sanity checks. Verify that all required information was found,
-     * including the queue file end marker.
-     */
-    if (message->rcpt_unread < 0
-       || (message->rcpt_offset == 0 && message->rcpt_unread != 0)) {
-       msg_warn("%s: rcpt count mismatch (%d)",
-                message->queue_id, message->rcpt_unread);
-       message->rcpt_unread = 0;
-    }
-    if (message->arrival_time == 0
-       || message->sender == 0
-       || message->data_offset == 0
-       || (message->rcpt_offset == 0 && rec_type != REC_TYPE_END)) {
-       msg_warn("%s: envelope records out of order", message->queue_id);
-       message->rcpt_offset = save_offset;     /* restore flag */
-       message->rcpt_unread += message->rcpt_list.len;
-       qmgr_rcpt_list_free(&message->rcpt_list);
-       qmgr_rcpt_list_init(&message->rcpt_list);
-       return (-1);
-    } else {
-       return (0);
-    }
-}
-
-/* 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)
-{
-    QMGR_RCPT *rcpt1 = (QMGR_RCPT *) p1;
-    QMGR_RCPT *rcpt2 = (QMGR_RCPT *) p2;
-    QMGR_QUEUE *queue1;
-    QMGR_QUEUE *queue2;
-    char   *at1;
-    char   *at2;
-    int     result;
-
-    /*
-     * Compare most significant to least significant recipient attributes.
-     */
-    if ((queue1 = rcpt1->queue) != 0 && (queue2 = rcpt2->queue) != 0) {
-
-       /*
-        * Compare message transport.
-        */
-       if ((result = strcasecmp(queue1->transport->name,
-                                queue2->transport->name)) != 0)
-           return (result);
-
-       /*
-        * Compare next-hop hostname.
-        */
-       if ((result = strcasecmp(queue1->name, queue2->name)) != 0)
-           return (result);
-    }
-
-    /*
-     * Compare recipient domain.
-     */
-    if ((at1 = strrchr(rcpt1->address, '@')) != 0
-       && (at2 = strrchr(rcpt2->address, '@')) != 0
-       && (result = strcasecmp(at1, at2)) != 0)
-       return (result);
-
-    /*
-     * Compare recipient address.
-     */
-    return (strcasecmp(rcpt1->address, rcpt2->address));
-}
-
-/* qmgr_message_sort - sort message recipient addresses by domain */
-
-static void qmgr_message_sort(QMGR_MESSAGE *message)
-{
-    qsort((char *) message->rcpt_list.info, message->rcpt_list.len,
-         sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare);
-    if (msg_verbose) {
-       QMGR_RCPT_LIST list = message->rcpt_list;
-       QMGR_RCPT *rcpt;
-
-       msg_info("start sorted recipient list");
-       for (rcpt = list.info; rcpt < list.info + list.len; rcpt++)
-           msg_info("qmgr_message_sort: %s", rcpt->address);
-       msg_info("end sorted recipient list");
-    }
-}
-
-/* qmgr_message_resolve - resolve recipients */
-
-static void qmgr_message_resolve(QMGR_MESSAGE *message)
-{
-    static ARGV *defer_xport_argv;
-    QMGR_RCPT_LIST list = message->rcpt_list;
-    QMGR_RCPT *recipient;
-    QMGR_TRANSPORT *transport = 0;
-    QMGR_QUEUE *queue = 0;
-    RESOLVE_REPLY reply;
-    const char *newloc;
-    char   *at;
-    char  **cpp;
-    char   *domain;
-    const char *junk;
-    char   *nexthop;
-    int     len;
-
-#define STREQ(x,y)     (strcasecmp(x,y) == 0)
-#define STR            vstring_str
-#define LEN            VSTRING_LEN
-#define UPDATE(ptr,new)        { myfree(ptr); ptr = mystrdup(new); }
-
-    resolve_clnt_init(&reply);
-    for (recipient = list.info; recipient < list.info + list.len; recipient++) {
-
-       /*
-        * This may be a bit late in the game, but it is the most convenient
-        * place to scrutinize the destination address syntax. We have a
-        * complete queue file, so bouncing is easy. That luxury is not
-        * available to the cleanup service. The main issue is that we want
-        * to have this test in one place, instead of having to do this in
-        * every front-ent program.
-        */
-       if ((at = strrchr(recipient->address, '@')) != 0
-           && (at + 1)[strspn(at + 1, "[]0123456789.")] != 0
-           && valid_hostname(at + 1) == 0) {
-           qmgr_bounce_recipient(message, recipient,
-                                 "bad host/domain syntax: \"%s\"", at + 1);
-           continue;
-       }
-
-       /*
-        * Resolve the destination to (transport, nexthop, address). The
-        * result address may differ from the one specified by the sender.
-        */
-       resolve_clnt_query(recipient->address, &reply);
-       if (message->filter_xport) {
-           vstring_strcpy(reply.transport, message->filter_xport);
-           if ((nexthop = split_at(STR(reply.transport), ':')) == 0
-               || *nexthop == 0)
-               nexthop = var_myhostname;
-           vstring_strcpy(reply.nexthop, nexthop);
-       } else {
-           if (!STREQ(recipient->address, STR(reply.recipient)))
-               UPDATE(recipient->address, STR(reply.recipient));
-       }
-
-       /*
-        * XXX The nexthop destination is also used as lookup key for the
-        * per-destination queue. Fold the nexthop to lower case so that we
-        * don't have multiple queues for the same site.
-        */
-       lowercase(STR(reply.nexthop));
-
-       /*
-        * Bounce recipients that have moved. We do it here instead of in the
-        * local delivery agent. The benefit is that we can bounce mail for
-        * virtual addresses, not just local addresses only, and that there
-        * is no need to run a local delivery agent just for the sake of
-        * relocation notices. The downside is that this table has no effect
-        * on local alias expansion results, so that mail will have to make
-        * almost an entire iteration through the mail system.
-        */
-#define IGNORE_ADDR_EXTENSION  ((char **) 0)
-
-       if (qmgr_relocated != 0) {
-           if ((newloc = mail_addr_find(qmgr_relocated, recipient->address,
-                                        IGNORE_ADDR_EXTENSION)) != 0) {
-               qmgr_bounce_recipient(message, recipient,
-                                     "user has moved to %s", newloc);
-               continue;
-           } else if (dict_errno != 0) {
-               qmgr_defer_recipient(message, recipient->address,
-                                    "relocated map lookup failure");
-               continue;
-           }
-       }
-
-       /*
-        * Bounce mail to non-existent users in virtual domains.
-        */
-       if (qmgr_virtual != 0
-           && (at = strrchr(recipient->address, '@')) != 0
-           && !resolve_local(at + 1)) {
-           domain = lowercase(mystrdup(at + 1));
-           junk = maps_find(qmgr_virtual, domain, 0);
-           myfree(domain);
-           if (junk) {
-               qmgr_bounce_recipient(message, recipient,
-                               "unknown user: \"%s\"", recipient->address);
-               continue;
-           }
-       }
-
-       /*
-        * Bounce recipient addresses that start with `-'. External commands
-        * may misinterpret such addresses as command-line options.
-        * 
-        * In theory I could say people should always carefully set up their
-        * master.cf pipe mailer entries with `--' before the first
-        * non-option argument, but mistakes will happen regardless.
-        * 
-        * Therefore the protection is put in place here, in the queue manager,
-        * where it cannot be bypassed.
-        */
-       if (var_allow_min_user == 0 && recipient->address[0] == '-') {
-           qmgr_bounce_recipient(message, recipient,
-                                 "invalid recipient syntax: \"%s\"",
-                                 recipient->address);
-           continue;
-       }
-
-       /*
-        * Queues are identified by the transport name and by the next-hop
-        * hostname. When the destination is local (no next hop), derive the
-        * queue name from the recipient name. XXX Should split the address
-        * on the recipient delimiter if one is defined, but doing a proper
-        * job requires knowledge of local aliases. Yuck! I don't want to
-        * duplicate delivery-agent specific knowledge in the queue manager.
-        * XXX The nexthop field is overloaded to serve as destination and as
-        * queue name. Should have separate fields for queue name and for
-        * destination.
-        */
-       if ((at = strrchr(STR(reply.recipient), '@')) == 0
-           || resolve_local(at + 1)) {
-           len = (at != 0 ? (at - STR(reply.recipient))
-                  : strlen(STR(reply.recipient)));
-           VSTRING_SPACE(reply.nexthop, len + 1);
-           memmove(STR(reply.nexthop) + len + 1, STR(reply.nexthop),
-                   LEN(reply.nexthop) + 1);
-           memcpy(STR(reply.nexthop), STR(reply.recipient), len);
-           STR(reply.nexthop)[len] = '@';
-           lowercase(STR(reply.nexthop));
-
-           /*
-            * Discard mail to the local double bounce address here, so this
-            * system can run without a local delivery agent. They'd still
-            * have to configure something for mail directed to the local
-            * postmaster, though, but that is an RFC requirement anyway.
-            */
-           if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
-                           at - STR(reply.recipient)) == 0
-               && !var_double_bounce_sender[at - STR(reply.recipient)]) {
-               sent(message->queue_id, recipient->address,
-                    "none", message->arrival_time, "discarded");
-               deliver_completed(message->fp, recipient->offset);
-               msg_warn("%s: undeliverable postmaster notification discarded",
-                        message->queue_id);
-               continue;
-           }
-       }
-
-       /*
-        * Optionally defer deliveries over specific transports, unless the
-        * restriction is lifted temporarily.
-        */
-       if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) {
-           if (defer_xport_argv == 0)
-               defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,");
-           for (cpp = defer_xport_argv->argv; *cpp; cpp++)
-               if (strcasecmp(*cpp, STR(reply.transport)) == 0)
-                   break;
-           if (*cpp) {
-               qmgr_defer_recipient(message, recipient->address,
-                                    "deferred transport");
-               continue;
-           }
-       }
-
-       /*
-        * XXX Gross hack alert. We want to group recipients by transport and
-        * by next-hop hostname, in order to minimize the number of network
-        * transactions. However, it would be wasteful to have an in-memory
-        * resolver reply structure for each in-core recipient. Instead, we
-        * bind each recipient to an in-core queue instance which is needed
-        * anyway. That gives all information needed for recipient grouping.
-        */
-
-       /*
-        * Look up or instantiate the proper transport.
-        */
-       if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
-           if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
-               transport = qmgr_transport_create(STR(reply.transport));
-           queue = 0;
-       }
-
-       /*
-        * This transport is dead. Defer delivery to this recipient.
-        */
-       if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
-           qmgr_defer_recipient(message, recipient->address, transport->reason);
-           continue;
-       }
-
-       /*
-        * This transport is alive. Find or instantiate a queue for this
-        * recipient.
-        */
-       if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) {
-           if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0)
-               queue = qmgr_queue_create(transport, STR(reply.nexthop));
-       }
-
-       /*
-        * This queue is dead. Defer delivery to this recipient.
-        */
-       if (queue->window == 0) {
-           qmgr_defer_recipient(message, recipient->address, queue->reason);
-           continue;
-       }
-
-       /*
-        * This queue is alive. Bind this recipient to this queue instance.
-        */
-       recipient->queue = queue;
-    }
-    resolve_clnt_free(&reply);
-}
-
-/* qmgr_message_assign - assign recipients to specific delivery requests */
-
-static void qmgr_message_assign(QMGR_MESSAGE *message)
-{
-    QMGR_RCPT_LIST list = message->rcpt_list;
-    QMGR_RCPT *recipient;
-    QMGR_ENTRY *entry = 0;
-    QMGR_QUEUE *queue;
-    QMGR_JOB *job = 0;
-    QMGR_PEER *peer = 0;
-
-    /*
-     * Try to bundle as many recipients in a delivery request as we can. When
-     * the recipient resolves to the same site and transport as the previous
-     * recipient, do not create a new queue entry, just move that recipient
-     * to the recipient list of the existing queue entry. All this provided
-     * that we do not exceed the transport-specific limit on the number of
-     * recipients per transaction. Skip recipients with a dead transport or
-     * destination.
-     */
-#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
-
-    for (recipient = list.info; recipient < list.info + list.len; recipient++) {
-       if ((queue = recipient->queue) != 0) {
-           if (message->single_rcpt || entry == 0 || entry->queue != queue
-               || !LIMIT_OK(queue->transport->recipient_limit,
-                            entry->rcpt_list.len)) {
-               if (job == 0 || queue->transport != job->transport) {
-                   job = qmgr_job_obtain(message, queue->transport);
-                   peer = 0;
-               }
-               if (peer == 0 || queue != peer->queue) {
-                   if ((peer = qmgr_peer_find(job, queue)) == 0)
-                       peer = qmgr_peer_create(job, queue);
-               }
-               entry = qmgr_entry_create(peer, message);
-               job->read_entries++;
-           }
-           qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset, recipient->address);
-           job->rcpt_count++;
-           message->rcpt_count++;
-           qmgr_recipient_count++;
-       }
-    }
-    qmgr_rcpt_list_free(&message->rcpt_list);
-    qmgr_rcpt_list_init(&message->rcpt_list);
-}
-
-/* qmgr_message_move_limits - recycle unused recipient slots */
-
-static void qmgr_message_move_limits(QMGR_MESSAGE *message)
-{
-    QMGR_JOB *job;
-
-    for (job = message->job_list.next; job; job = job->message_peers.next)
-       qmgr_job_move_limits(job);
-}
-
-/* qmgr_message_free - release memory for in-core message structure */
-
-void    qmgr_message_free(QMGR_MESSAGE *message)
-{
-    QMGR_JOB *job;
-
-    if (message->refcount != 0)
-       msg_panic("qmgr_message_free: reference len: %d", message->refcount);
-    if (message->fp)
-       msg_panic("qmgr_message_free: queue file is open");
-    while ((job = message->job_list.next) != 0)
-       qmgr_job_free(job);
-    myfree(message->queue_id);
-    myfree(message->queue_name);
-    if (message->sender)
-       myfree(message->sender);
-    if (message->errors_to)
-       myfree(message->errors_to);
-    if (message->return_receipt)
-       myfree(message->return_receipt);
-    if (message->filter_xport)
-       myfree(message->filter_xport);
-    if (message->inspect_xport)
-       myfree(message->inspect_xport);
-    qmgr_rcpt_list_free(&message->rcpt_list);
-    qmgr_message_count--;
-    myfree((char *) message);
-}
-
-/* qmgr_message_alloc - create in-core message structure */
-
-QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
-                                        int qflags)
-{
-    char   *myname = "qmgr_message_alloc";
-    QMGR_MESSAGE *message;
-
-    if (msg_verbose)
-       msg_info("%s: %s %s", myname, queue_name, queue_id);
-
-    /*
-     * Create an in-core message structure.
-     */
-    message = qmgr_message_create(queue_name, queue_id, qflags);
-
-    /*
-     * Extract message envelope information: time of arrival, sender address,
-     * recipient addresses. Skip files with malformed envelope information.
-     */
-#define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
-
-    if (qmgr_message_open(message) < 0) {
-       qmgr_message_free(message);
-       return (0);
-    }
-    if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) {
-       msg_info("%s: skipped, still being delivered", queue_id);
-       qmgr_message_close(message);
-       qmgr_message_free(message);
-       return (QMGR_MESSAGE_LOCKED);
-    }
-    if (qmgr_message_read(message) < 0) {
-       qmgr_message_close(message);
-       qmgr_message_free(message);
-       return (0);
-    } else {
-
-       /*
-        * Reset the defer log. This code should not be here, but we must
-        * reset the defer log *after* acquiring the exclusive lock on the
-        * queue file and *before* resolving new recipients. Since all those
-        * operations are encapsulated so nicely by this routine, the defer
-        * log reset has to be done here as well.
-        */
-       if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
-           msg_fatal("%s: %s: remove %s %s: %m", myname,
-                     queue_id, MAIL_QUEUE_DEFER, queue_id);
-       qmgr_message_sort(message);
-       qmgr_message_resolve(message);
-       qmgr_message_sort(message);
-       qmgr_message_assign(message);
-       qmgr_message_close(message);
-       if (message->rcpt_offset == 0)
-           qmgr_message_move_limits(message);
-       return (message);
-    }
-}
-
-/* qmgr_message_realloc - refresh in-core message structure */
-
-QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message)
-{
-    char   *myname = "qmgr_message_realloc";
-
-    /*
-     * Sanity checks.
-     */
-    if (message->rcpt_offset <= 0)
-       msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset);
-    if (msg_verbose)
-       msg_info("%s: %s %s offset %ld", myname, message->queue_name,
-                message->queue_id, message->rcpt_offset);
-
-    /*
-     * Extract recipient addresses. Skip files with malformed envelope
-     * information.
-     */
-    if (qmgr_message_open(message) < 0)
-       return (0);
-    if (qmgr_message_read(message) < 0) {
-       qmgr_message_close(message);
-       return (0);
-    } else {
-       qmgr_message_sort(message);
-       qmgr_message_resolve(message);
-       qmgr_message_sort(message);
-       qmgr_message_assign(message);
-       qmgr_message_close(message);
-       if (message->rcpt_offset == 0)
-           qmgr_message_move_limits(message);
-       return (message);
-    }
-}
diff --git a/postfix/src/nqmgr/qmgr_move.c b/postfix/src/nqmgr/qmgr_move.c
deleted file mode 100644 (file)
index 7f86197..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_move 3
-/* SUMMARY
-/*     move queue entries to another queue
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     void    qmgr_move(from, to, time_stamp)
-/*     const char *from;
-/*     const char *to;
-/*     time_t  time_stamp;
-/* DESCRIPTION
-/*     The \fBqmgr_move\fR routine scans the \fIfrom\fR queue for entries
-/*     with valid queue names and moves them to the \fIto\fR queue.
-/*     If \fItime_stamp\fR is non-zero, the queue file time stamps are
-/*     set to the specified value.
-/*     Entries with invalid names are left alone. No attempt is made to
-/*     look for other badness such as multiple links or weird file types.
-/*     These issues are dealt with when a queue file is actually opened.
-/* 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 <string.h>
-#include <utime.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <scan_dir.h>
-#include <recipient_list.h>
-
-/* Global library. */
-
-#include <mail_queue.h>
-#include <mail_scan_dir.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_move - move queue entries to another queue, leave bad files alone */
-
-void    qmgr_move(const char *src_queue, const char *dst_queue,
-                         time_t time_stamp)
-{
-    char   *myname = "qmgr_move";
-    SCAN_DIR *queue_dir;
-    char   *queue_id;
-    struct utimbuf tbuf;
-    const char *path;
-
-    if (strcmp(src_queue, dst_queue) == 0)
-       msg_panic("%s: source queue %s is destination", myname, src_queue);
-    if (msg_verbose)
-       msg_info("start move queue %s -> %s", src_queue, dst_queue);
-
-    queue_dir = scan_dir_open(src_queue);
-    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;
-               path = mail_queue_path((VSTRING *) 0, src_queue, queue_id);
-               if (utime(path, &tbuf) < 0)
-                   msg_fatal("%s: update %s time stamps: %m", myname, path);
-           }
-           if (mail_queue_rename(queue_id, src_queue, dst_queue))
-               msg_fatal("%s: rename %s from %s to %s: %m",
-                         myname, queue_id, src_queue, dst_queue);
-           if (msg_verbose)
-               msg_info("%s: moved %s from %s to %s",
-                        myname, queue_id, src_queue, dst_queue);
-       } else {
-           msg_warn("%s: ignored: queue %s id %s",
-                    myname, src_queue, queue_id);
-       }
-    }
-    scan_dir_close(queue_dir);
-
-    if (msg_verbose)
-       msg_info("end move queue %s -> %s", src_queue, dst_queue);
-}
diff --git a/postfix/src/nqmgr/qmgr_peer.c b/postfix/src/nqmgr/qmgr_peer.c
deleted file mode 100644 (file)
index 9b61e64..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_peer 3
-/* SUMMARY
-/*     per-job peers
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_PEER *qmgr_peer_create(job, queue)
-/*     QMGR_JOB *job;
-/*     QMGR_QUEUE *queue;
-/*
-/*     QMGR_PEER *qmgr_peer_find(job, queue)
-/*     QMGR_JOB *job;
-/*     QMGR_QUEUE *queue;
-/*
-/*     void qmgr_peer_free(peer)
-/*     QMGR_PEER *peer;
-/*
-/*     QMGR_PEER *qmgr_peer_select(job)
-/*     QMGR_JOB *job;
-/*
-/* DESCRIPTION
-/*     These routines add/delete/manipulate per-job peers.
-/*     Each queue corresponds to a specific job and destination.
-/*      It is similar to per-transport queue structure, but groups
-/*      only the entries of the given job.
-/*
-/*     qmgr_peer_create() creates an empty peer structure for the named
-/*     job and destination. It is an error to call this function
-/*     if a peer for given combination already exists.
-/*
-/*     qmgr_peer_find() looks up the peer for the named destination
-/*     for the named job. A null result means that the peer
-/*     was not found.
-/*
-/*     qmgr_peer_free() disposes of a per-job peer after all
-/*     its entries have been taken care of. It is an error to dispose
-/*     of a peer still in use.
-/*
-/*     qmgr_peer_select() attempts to find a peer of named job that
-/*     has messages pending delivery.  This routine implements
-/*     round-robin search among job's peers.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure.
-/* LICENSE
-/* .ad
-/* .fi
-/*     The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/*     Patrik Rak
-/*     patrik@raxoft.cz
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <htable.h>
-#include <mymalloc.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_peer_create - create and initialize message peer structure */
-
-QMGR_PEER *qmgr_peer_create(QMGR_JOB *job, QMGR_QUEUE *queue)
-{
-    QMGR_PEER *peer;
-
-    peer = (QMGR_PEER *) mymalloc(sizeof(QMGR_PEER));
-    peer->queue = queue;
-    peer->job = job;
-    QMGR_LIST_APPEND(job->peer_list, peer, peers);
-    htable_enter(job->peer_byname, queue->name, (char *) peer);
-    peer->refcount = 0;
-    QMGR_LIST_INIT(peer->entry_list);
-    return (peer);
-}
-
-/* qmgr_peer_free - release peer structure */
-
-void    qmgr_peer_free(QMGR_PEER *peer)
-{
-    char   *myname = "qmgr_peer_free";
-    QMGR_JOB *job = peer->job;
-    QMGR_QUEUE *queue = peer->queue;
-
-    /*
-     * Sanity checks. It is an error to delete a referenced peer structure.
-     */
-    if (peer->refcount != 0)
-       msg_panic("%s: refcount: %d", myname, peer->refcount);
-    if (peer->entry_list.next != 0)
-       msg_panic("%s: entry list not empty: %s", myname, queue->name);
-
-    QMGR_LIST_UNLINK(job->peer_list, QMGR_PEER *, peer, peers);
-    htable_delete(job->peer_byname, queue->name, (void (*) (char *)) 0);
-    myfree((char *) peer);
-}
-
-/* qmgr_peer_find - lookup peer associated with given job and queue */
-
-QMGR_PEER *qmgr_peer_find(QMGR_JOB *job, QMGR_QUEUE *queue)
-{
-    return ((QMGR_PEER *) htable_find(job->peer_byname, queue->name));
-}
-
-/* qmgr_peer_select - select next peer suitable for delivery within given job */
-
-QMGR_PEER *qmgr_peer_select(QMGR_JOB *job)
-{
-    QMGR_PEER *peer;
-    QMGR_QUEUE *queue;
-
-    /*
-     * If we find a suitable site, rotate the list to enforce round-robin
-     * selection. See similar selection code in qmgr_transport_select().
-     */
-    for (peer = job->peer_list.next; peer; peer = peer->peers.next) {
-       queue = peer->queue;
-       if (queue->window > queue->busy_refcount && peer->entry_list.next != 0) {
-           QMGR_LIST_ROTATE(job->peer_list, peer, peers);
-           if (msg_verbose)
-               msg_info("qmgr_peer_select: %s %s %s (%d of %d)",
-               job->message->queue_id, queue->transport->name, queue->name,
-                        queue->busy_refcount + 1, queue->window);
-           return (peer);
-       }
-    }
-    return (0);
-}
diff --git a/postfix/src/nqmgr/qmgr_queue.c b/postfix/src/nqmgr/qmgr_queue.c
deleted file mode 100644 (file)
index ef7d696..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_queue 3
-/* SUMMARY
-/*     per-destination queues
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     int     qmgr_queue_count;
-/*
-/*     QMGR_QUEUE *qmgr_queue_create(transport, site)
-/*     QMGR_TRANSPORT *transport;
-/*     const char *site;
-/*
-/*     void    qmgr_queue_done(queue)
-/*     QMGR_QUEUE *queue;
-/*
-/*     QMGR_QUEUE *qmgr_queue_find(transport, site)
-/*     QMGR_TRANSPORT *transport;
-/*     const char *site;
-/*
-/*     void    qmgr_queue_throttle(queue, reason)
-/*     QMGR_QUEUE *queue;
-/*     const char *reason;
-/*
-/*     void    qmgr_queue_unthrottle(queue)
-/*     QMGR_QUEUE *queue;
-/* DESCRIPTION
-/*     These routines add/delete/manipulate per-destination queues.
-/*     Each queue corresponds to a specific transport and destination.
-/*     Each queue has a `todo' list of delivery requests for that
-/*     destination, and a `busy' list of delivery requests in progress.
-/*
-/*     qmgr_queue_count is a global counter for the total number
-/*     of in-core queue structures.
-/*
-/*     qmgr_queue_create() creates an empty queue for the named
-/*     transport and destination. The queue is given an initial
-/*     concurrency limit as specified with the
-/*     \fIinitial_destination_concurrency\fR configuration parameter,
-/*     provided that it does not exceed the transport-specific
-/*     concurrency limit.
-/*
-/*     qmgr_queue_done() disposes of a per-destination queue after all
-/*     its entries have been taken care of. It is an error to dispose
-/*     of a dead queue.
-/*
-/*     qmgr_queue_find() looks up the queue for the named destination
-/*     for the named transport. A null result means that the queue
-/*     was not found.
-/*
-/*     qmgr_queue_throttle() handles a delivery error, and decrements the
-/*     concurrency limit for the destination. When the concurrency limit
-/*     for a destination becomes zero, qmgr_queue_throttle() starts a timer
-/*     to re-enable delivery to the destination after a configurable delay.
-/*
-/*     qmgr_queue_unthrottle() undoes qmgr_queue_throttle()'s effects.
-/*     The concurrency limit for the destination is incremented,
-/*     provided that it does not exceed the destination concurrency
-/*     limit specified for the transport. This routine implements
-/*     "slow open" mode, and eliminates the "thundering herd" problem.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure.
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <time.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <events.h>
-#include <htable.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-#include <recipient_list.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-int     qmgr_queue_count;
-
-/* qmgr_queue_unthrottle_wrapper - in case (char *) != (struct *) */
-
-static void qmgr_queue_unthrottle_wrapper(int unused_event, char *context)
-{
-    QMGR_QUEUE *queue = (QMGR_QUEUE *) context;
-
-    /*
-     * This routine runs when a wakeup timer goes off; it does not run in the
-     * context of some queue manipulation. Therefore, it is safe to discard
-     * this in-core queue when it is empty and when this site is not dead.
-     */
-    qmgr_queue_unthrottle(queue);
-    if (queue->window > 0 && queue->todo.next == 0 && queue->busy.next == 0)
-       qmgr_queue_done(queue);
-}
-
-/* qmgr_queue_unthrottle - give this destination another chance */
-
-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);
-
-    /*
-     * Special case when this site was dead.
-     */
-    if (queue->window == 0) {
-       event_cancel_timer(qmgr_queue_unthrottle_wrapper, (char *) queue);
-       if (queue->reason == 0)
-           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;
-    }
-
-    /*
-     * Increase the destination's concurrency limit until we reach the
-     * transport's concurrency limit. Allow for a margin the size of the
-     * initial destination concurrency, so that we're not too gentle.
-     */
-    if (transport->dest_concurrency_limit == 0
-       || transport->dest_concurrency_limit > queue->window)
-       if (queue->window <= queue->busy_refcount + transport->init_dest_concurrency)
-           queue->window++;
-}
-
-/* qmgr_queue_throttle - handle destination delivery failure */
-
-void    qmgr_queue_throttle(QMGR_QUEUE *queue, const char *reason)
-{
-    char   *myname = "qmgr_queue_throttle";
-
-    /*
-     * Sanity checks.
-     */
-    if (queue->reason)
-       msg_panic("%s: queue %s: spurious reason %s",
-                 myname, queue->name, queue->reason);
-    if (msg_verbose)
-       msg_info("%s: queue %s: %s", myname, queue->name, reason);
-
-    /*
-     * Decrease the destination's concurrency limit until we reach zero, at
-     * 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.
-     */
-    if (queue->window > 0)
-       queue->window--;
-
-    /*
-     * Special case for a site that just was declared dead.
-     */
-    if (queue->window == 0) {
-       queue->reason = mystrdup(reason);
-       event_request_timer(qmgr_queue_unthrottle_wrapper,
-                           (char *) queue, var_min_backoff_time);
-    }
-}
-
-/* qmgr_queue_done - delete in-core queue for site */
-
-void    qmgr_queue_done(QMGR_QUEUE *queue)
-{
-    char   *myname = "qmgr_queue_done";
-    QMGR_TRANSPORT *transport = queue->transport;
-
-    /*
-     * Sanity checks. It is an error to delete an in-core queue with pending
-     * messages or timers.
-     */
-    if (queue->busy_refcount != 0 || queue->todo_refcount != 0)
-       msg_panic("%s: refcount: %d", myname,
-                 queue->busy_refcount + queue->todo_refcount);
-    if (queue->todo.next || queue->busy.next)
-       msg_panic("%s: queue not empty: %s", myname, queue->name);
-    if (queue->window <= 0)
-       msg_panic("%s: window %d", myname, queue->window);
-    if (queue->reason)
-       msg_panic("%s: queue %s: spurious reason %s",
-                 myname, queue->name, queue->reason);
-
-    /*
-     * Clean up this in-core queue.
-     */
-    QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue, peers);
-    htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0);
-    myfree(queue->name);
-    qmgr_queue_count--;
-    myfree((char *) queue);
-}
-
-/* qmgr_queue_create - create in-core queue for site */
-
-QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site)
-{
-    QMGR_QUEUE *queue;
-
-    /*
-     * If possible, choose an initial concurrency of > 1 so that one bad
-     * message or one bad network won't slow us down unnecessarily.
-     */
-
-    queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE));
-    qmgr_queue_count++;
-    queue->name = mystrdup(site);
-    queue->todo_refcount = 0;
-    queue->busy_refcount = 0;
-    queue->transport = transport;
-    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, peers);
-    htable_enter(transport->queue_byname, site, (char *) queue);
-    return (queue);
-}
-
-/* qmgr_queue_find - find in-core queue for site */
-
-QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *site)
-{
-    return ((QMGR_QUEUE *) htable_find(transport->queue_byname, site));
-}
diff --git a/postfix/src/nqmgr/qmgr_rcpt_list.c b/postfix/src/nqmgr/qmgr_rcpt_list.c
deleted file mode 100644 (file)
index 2bb292e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_rcpt_list 3
-/* SUMMARY
-/*     in-core recipient structures
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     void    qmgr_rcpt_list_init(list)
-/*     QMGR_RCPT_LIST *list;
-/*
-/*     void    qmgr_rcpt_list_add(list, offset, recipient)
-/*     QMGR_RCPT_LIST *list;
-/*     long    offset;
-/*     const char *recipient;
-/*
-/*     void    qmgr_rcpt_list_free(list)
-/*     QMGR_RCPT_LIST *list;
-/* DESCRIPTION
-/*     This module maintains lists of queue manager recipient structures.
-/*     These structures are extended versions of the structures maintained
-/*     by the recipient_list(3) module. The extension is that the queue
-/*     manager version of a recipient can have a reference to a queue
-/*     structure.
-/*
-/*     qmgr_rcpt_list_init() creates an empty recipient structure list.
-/*     The list argument is initialized such that it can be given to
-/*     qmgr_rcpt_list_add() and qmgr_rcpt_list_free().
-/*
-/*     qmgr_rcpt_list_add() adds a recipient to the specified list.
-/*     The recipient name is copied.
-/*
-/*     qmgr_rcpt_list_free() releases memory for the specified list
-/*     of recipient structures.
-/* SEE ALSO
-/*     qmgr_rcpt_list(3h) data structure
-/*     recipient_list(3) same code, different data structure.
-/* DIAGNOSTICS
-/*     Fatal errors: memory allocation.
-/* 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 <mymalloc.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_rcpt_list_init - initialize */
-
-void    qmgr_rcpt_list_init(QMGR_RCPT_LIST *list)
-{
-    list->avail = 1;
-    list->len = 0;
-    list->info = (QMGR_RCPT *) mymalloc(sizeof(QMGR_RCPT));
-}
-
-/* qmgr_rcpt_list_add - add rcpt to list */
-
-void    qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *rcpt)
-{
-    if (list->len >= list->avail) {
-       list->avail *= 2;
-       list->info = (QMGR_RCPT *)
-           myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT));
-    }
-    list->info[list->len].address = mystrdup(rcpt);
-    list->info[list->len].offset = offset;
-    list->info[list->len].queue = 0;
-    list->len++;
-}
-
-/* qmgr_rcpt_list_free - release memory for in-core recipient structure */
-
-void    qmgr_rcpt_list_free(QMGR_RCPT_LIST *list)
-{
-    QMGR_RCPT *rcpt;
-
-    for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
-       myfree(rcpt->address);
-    myfree((char *) list->info);
-}
diff --git a/postfix/src/nqmgr/qmgr_scan.c b/postfix/src/nqmgr/qmgr_scan.c
deleted file mode 100644 (file)
index e0d9fc0..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_scan 3
-/* SUMMARY
-/*     queue scanning
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_SCAN *qmgr_scan_create(queue_name)
-/*     const char *queue_name;
-/*
-/*     char    *qmgr_scan_next(scan_info)
-/*     QMGR_SCAN *scan_info;
-/*
-/*     void    qmgr_scan_request(scan_info, flags)
-/*     QMGR_SCAN *scan_info;
-/*     int     flags;
-/* DESCRIPTION
-/*     This module implements queue scans. A queue scan always runs
-/*     to completion, so that all files get a fair chance. The caller
-/*     can request that a queue scan be restarted once it completes.
-/*
-/*     qmgr_scan_create() creates a context for scanning the named queue,
-/*     but does not start a queue scan.
-/*
-/*     qmgr_scan_next() returns the base name of the next queue file.
-/*     A null pointer means that no file was found. qmgr_scan_next()
-/*     automagically restarts a queue scan when a scan request had
-/*     arrived while the scan was in progress.
-/*
-/*     qmgr_scan_request() records a request for the next queue scan. The
-/*     flags argument is the bit-wise OR of zero or more of the following,
-/*     unrecognized flags being ignored:
-/* .IP QMGR_FLUSH_DEAD
-/*     Forget state information about dead hosts or transports. This
-/*     request takes effect upon the next queue scan.
-/* .IP QMGR_SCAN_ALL
-/*     Ignore queue file time stamps.
-/*     This flag is passed on to the qmgr_active_feed() routine.
-/* .IP QMGR_SCAN_START
-/*     Start a queue scan when none is in progress, or restart the
-/*     current scan upon completion.
-/* DIAGNOSTICS
-/*     Fatal: out of memory.
-/*     Panic: interface violations, internal consistency errors.
-/* 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 <scan_dir.h>
-
-/* Global library. */
-
-#include <mail_scan_dir.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-/* qmgr_scan_start - start queue scan */
-
-static void qmgr_scan_start(QMGR_SCAN *scan_info)
-{
-    char   *myname = "qmgr_scan_start";
-
-    /*
-     * Sanity check.
-     */
-    if (scan_info->handle)
-       msg_panic("%s: %s queue scan in progress",
-                 myname, scan_info->queue);
-
-    /*
-     * Give the poor tester a clue.
-     */
-    if (msg_verbose)
-       msg_info("%s: %sstart %s queue scan",
-                myname,
-                scan_info->nflags & QMGR_SCAN_START ? "re" : "",
-                scan_info->queue);
-
-    /*
-     * Optionally forget all dead host information.
-     */
-    if (scan_info->nflags & QMGR_FLUSH_DEAD)
-       qmgr_enable_all();
-
-    /*
-     * Start or restart the scan.
-     */
-    scan_info->flags = scan_info->nflags;
-    scan_info->nflags = 0;
-    scan_info->handle = scan_dir_open(scan_info->queue);
-}
-
-/* qmgr_scan_request - request for future scan */
-
-void    qmgr_scan_request(QMGR_SCAN *scan_info, int flags)
-{
-
-    /*
-     * If a scan is in progress, just record the request.
-     */
-    scan_info->nflags |= flags;
-    if (scan_info->handle == 0 && (flags & QMGR_SCAN_START) != 0) {
-       scan_info->nflags &= ~QMGR_SCAN_START;
-       qmgr_scan_start(scan_info);
-    }
-}
-
-/* qmgr_scan_next - look for next queue file */
-
-char   *qmgr_scan_next(QMGR_SCAN *scan_info)
-{
-    char   *path = 0;
-
-    /*
-     * Restart the scan if we reach the end and a queue scan request has
-     * arrived in the mean time.
-     */
-    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 = mail_scan_dir_next(scan_info->handle);
-    }
-    return (path);
-}
-
-/* qmgr_scan_create - create queue scan context */
-
-QMGR_SCAN *qmgr_scan_create(const char *queue)
-{
-    QMGR_SCAN *scan_info;
-
-    scan_info = (QMGR_SCAN *) mymalloc(sizeof(*scan_info));
-    scan_info->queue = mystrdup(queue);
-    scan_info->flags = scan_info->nflags = 0;
-    scan_info->handle = 0;
-    return (scan_info);
-}
diff --git a/postfix/src/nqmgr/qmgr_transport.c b/postfix/src/nqmgr/qmgr_transport.c
deleted file mode 100644 (file)
index 7fef4c7..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*++
-/* NAME
-/*     qmgr_transport 3
-/* SUMMARY
-/*     per-transport data structures
-/* SYNOPSIS
-/*     #include "qmgr.h"
-/*
-/*     QMGR_TRANSPORT *qmgr_transport_create(name)
-/*     const char *name;
-/*
-/*     QMGR_TRANSPORT *qmgr_transport_find(name)
-/*     const char *name;
-/*
-/*     QMGR_TRANSPORT *qmgr_transport_select()
-/*
-/*     void    qmgr_transport_alloc(transport, notify)
-/*     QMGR_TRANSPORT *transport;
-/*     void    (*notify)(QMGR_TRANSPORT *transport, VSTREAM *fp);
-/*
-/*     void    qmgr_transport_throttle(transport, reason)
-/*     QMGR_TRANSPORT *transport;
-/*     const char *reason;
-/*
-/*     void    qmgr_transport_unthrottle(transport)
-/*     QMGR_TRANSPORT *transport;
-/* DESCRIPTION
-/*     This module organizes the world by message transport type.
-/*     Each transport can have zero or more destination queues
-/*     associated with it.
-/*
-/*     qmgr_transport_create() instantiates a data structure for the
-/*     named transport type.
-/*
-/*     qmgr_transport_find() looks up an existing message transport
-/*     data structure.
-/*
-/*     qmgr_transport_select() attempts to find a transport that
-/*     has messages pending delivery.  This routine implements
-/*     round-robin search among transports.
-/*
-/*     qmgr_transport_alloc() allocates a delivery process for the
-/*     specified transport type. Allocation is performed asynchronously.
-/*     When a process becomes available, the application callback routine
-/*     is invoked with as arguments the transport and a stream that
-/*     is connected to a delivery process. It is an error to call
-/*     qmgr_transport_alloc() while delivery process allocation for
-/*     the same transport is in progress.
-/*
-/*     qmgr_transport_throttle blocks further allocation of delivery
-/*     processes for the named transport. Attempts to throttle a
-/*     throttled transport are ignored.
-/*
-/*     qmgr_transport_unthrottle() undoes qmgr_transport_throttle().
-/*     Attempts to unthrottle a non-throttled transport are ignored.
-/* DIAGNOSTICS
-/*     Panic: consistency check failure. Fatal: out of memory.
-/* 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
-/*
-/*     Scheduler enhancements:
-/*     Patrik Rak
-/*     Modra 6
-/*     155 00, Prague, Czech Republic
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <unistd.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <htable.h>
-#include <events.h>
-#include <mymalloc.h>
-#include <vstream.h>
-#include <iostuff.h>
-
-/* Global library. */
-
-#include <mail_proto.h>
-#include <recipient_list.h>
-#include <mail_conf.h>
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "qmgr.h"
-
-HTABLE *qmgr_transport_byname;         /* transport by name */
-QMGR_TRANSPORT_LIST qmgr_transport_list;/* transports, round robin */
-
- /*
-  * A local structure to remember a delivery process allocation request.
-  */
-typedef struct QMGR_TRANSPORT_ALLOC QMGR_TRANSPORT_ALLOC;
-
-struct QMGR_TRANSPORT_ALLOC {
-    QMGR_TRANSPORT *transport;         /* transport context */
-    VSTREAM *stream;                   /* delivery service stream */
-    QMGR_TRANSPORT_ALLOC_NOTIFY notify;        /* application call-back routine */
-};
-
-/* qmgr_transport_unthrottle_wrapper - in case (char *) != (struct *) */
-
-static void qmgr_transport_unthrottle_wrapper(int unused_event, char *context)
-{
-    qmgr_transport_unthrottle((QMGR_TRANSPORT *) context);
-}
-
-/* qmgr_transport_unthrottle - open the throttle */
-
-void    qmgr_transport_unthrottle(QMGR_TRANSPORT *transport)
-{
-    char   *myname = "qmgr_transport_unthrottle";
-
-    /*
-     * This routine runs after expiration of the timer set by
-     * qmgr_transport_throttle(), or whenever a delivery transport has been
-     * used without malfunction. In either case, we enable delivery again if
-     * the transport was blocked, otherwise the request is ignored.
-     */
-    if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
-       if (msg_verbose)
-           msg_info("%s: transport %s", myname, transport->name);
-       transport->flags &= ~QMGR_TRANSPORT_STAT_DEAD;
-       if (transport->reason == 0)
-           msg_panic("%s: transport %s: null reason", myname, transport->name);
-       myfree(transport->reason);
-       transport->reason = 0;
-       event_cancel_timer(qmgr_transport_unthrottle_wrapper,
-                          (char *) transport);
-    }
-}
-
-/* qmgr_transport_throttle - disable delivery process allocation */
-
-void    qmgr_transport_throttle(QMGR_TRANSPORT *transport, const char *reason)
-{
-    char   *myname = "qmgr_transport_throttle";
-
-    /*
-     * We are unable to connect to a deliver process for this type of message
-     * transport. Instead of hosing the system by retrying in a tight loop,
-     * back off and disable this transport type for a while.
-     */
-    if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) == 0) {
-       if (msg_verbose)
-           msg_info("%s: transport %s: reason: %s",
-                    myname, transport->name, reason);
-       transport->flags |= QMGR_TRANSPORT_STAT_DEAD;
-       if (transport->reason)
-           msg_panic("%s: transport %s: spurious reason: %s",
-                     myname, transport->name, transport->reason);
-       transport->reason = mystrdup(reason);
-       event_request_timer(qmgr_transport_unthrottle_wrapper,
-                           (char *) transport, var_transport_retry_time);
-    }
-}
-
-/* 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)
-{
-    QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
-
-    /*
-     * This routine notifies the application when the request given to
-     * qmgr_transport_alloc() completes.
-     */
-    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.
-     */
-    event_disable_readwrite(vstream_fileno(alloc->stream));
-    alloc->transport->flags &= ~QMGR_TRANSPORT_STAT_BUSY;
-
-    /*
-     * Notify the requestor.
-     */
-    alloc->notify(alloc->transport, alloc->stream);
-    myfree((char *) alloc);
-}
-
-#ifdef UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
-
-/* qmgr_transport_connect - handle connection request completion */
-
-static void qmgr_transport_connect(int unused_event, char *context)
-{
-    QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
-
-    /*
-     * This code is necessary for some versions of LINUX, where connect(2)
-     * blocks until the application performs an accept(2). Reportedly, the
-     * same can happen on Solaris 2.5.1.
-     */
-    event_disable_readwrite(vstream_fileno(alloc->stream));
-    non_blocking(vstream_fileno(alloc->stream), BLOCKING);
-    event_enable_read(vstream_fileno(alloc->stream),
-                     qmgr_transport_event, (char *) alloc);
-}
-
-#endif
-
-/* qmgr_transport_select - select transport for allocation */
-
-QMGR_TRANSPORT *qmgr_transport_select(void)
-{
-    QMGR_TRANSPORT *xport;
-    QMGR_QUEUE *queue;
-
-    /*
-     * If we find a suitable transport, rotate the list of transports to
-     * effectuate round-robin selection. See similar selection code in
-     * qmgr_peer_select().
-     */
-#define STAY_AWAY (QMGR_TRANSPORT_STAT_BUSY | QMGR_TRANSPORT_STAT_DEAD)
-
-    for (xport = qmgr_transport_list.next; xport; xport = xport->peers.next) {
-       if (xport->flags & STAY_AWAY)
-           continue;
-       for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
-           if (queue->window > queue->busy_refcount && queue->todo.next != 0) {
-               QMGR_LIST_ROTATE(qmgr_transport_list, xport, peers);
-               if (msg_verbose)
-                   msg_info("qmgr_transport_select: %s", xport->name);
-               return (xport);
-           }
-       }
-    }
-    return (0);
-}
-
-/* qmgr_transport_alloc - allocate delivery process */
-
-void    qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOTIFY notify)
-{
-    QMGR_TRANSPORT_ALLOC *alloc;
-    VSTREAM *stream;
-
-    /*
-     * Sanity checks.
-     */
-    if (transport->flags & QMGR_TRANSPORT_STAT_DEAD)
-       msg_panic("qmgr_transport: dead transport: %s", transport->name);
-    if (transport->flags & QMGR_TRANSPORT_STAT_BUSY)
-       msg_panic("qmgr_transport: nested allocation: %s", transport->name);
-
-    /*
-     * Connect to the well-known port for this delivery service, and wake up
-     * when a process announces its availability. In the mean time, block out
-     * other delivery process allocation attempts for this transport. In case
-     * of problems, back off. Do not hose the system when it is in trouble
-     * already.
-     */
-#ifdef UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
-#define BLOCK_MODE     NON_BLOCKING
-#define ENABLE_EVENTS  event_enable_write
-#define EVENT_HANDLER  qmgr_transport_connect
-#else
-#define BLOCK_MODE     BLOCKING
-#define ENABLE_EVENTS  event_enable_read
-#define EVENT_HANDLER  qmgr_transport_event
-#endif
-
-    if ((stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name, BLOCK_MODE)) == 0) {
-       msg_warn("connect to transport %s: %m", transport->name);
-       qmgr_transport_throttle(transport, "transport is unavailable");
-       return;
-    }
-    alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc));
-    alloc->stream = stream;
-    alloc->transport = transport;
-    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_daemon_timeout);
-}
-
-/* qmgr_transport_create - create transport instance */
-
-QMGR_TRANSPORT *qmgr_transport_create(const char *name)
-{
-    QMGR_TRANSPORT *transport;
-
-    if (htable_find(qmgr_transport_byname, name) != 0)
-       msg_panic("qmgr_transport_create: transport exists: %s", name);
-    transport = (QMGR_TRANSPORT *) mymalloc(sizeof(QMGR_TRANSPORT));
-    transport->flags = 0;
-    transport->name = mystrdup(name);
-
-    /*
-     * Use global configuration settings or transport-specific settings.
-     */
-    transport->dest_concurrency_limit =
-       get_mail_conf_int2(name, _DEST_CON_LIMIT,
-                          var_dest_con_limit, 0, 0);
-    transport->recipient_limit =
-       get_mail_conf_int2(name, _DEST_RCPT_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->slot_cost = get_mail_conf_int2(name, _DELIVERY_SLOT_COST,
-                                             var_delivery_slot_cost, 0, 0);
-    transport->slot_loan = get_mail_conf_int2(name, _DELIVERY_SLOT_LOAN,
-                                             var_delivery_slot_loan, 0, 0);
-    transport->slot_loan_factor =
-       100 - get_mail_conf_int2(name, _DELIVERY_SLOT_DISCOUNT,
-                                var_delivery_slot_discount, 0, 100);
-    transport->min_slots = get_mail_conf_int2(name, _MIN_DELIVERY_SLOTS,
-                                             var_min_delivery_slots, 0, 0);
-    transport->rcpt_unused = get_mail_conf_int2(name, _XPORT_RCPT_LIMIT,
-                                               var_xport_rcpt_limit, 0, 0);
-    transport->rcpt_per_stack = get_mail_conf_int2(name, _STACK_RCPT_LIMIT,
-                                               var_stack_rcpt_limit, 0, 0);
-
-    transport->queue_byname = htable_create(0);
-    QMGR_LIST_INIT(transport->queue_list);
-    transport->job_byname = htable_create(0);
-    QMGR_LIST_INIT(transport->job_list);
-    QMGR_LIST_INIT(transport->job_stack);
-    transport->job_next_unread = 0;
-    transport->candidate_cache = 0;
-    transport->candidate_cache_time = (time_t) 0;
-    transport->reason = 0;
-    if (qmgr_transport_byname == 0)
-       qmgr_transport_byname = htable_create(10);
-    htable_enter(qmgr_transport_byname, name, (char *) transport);
-    QMGR_LIST_PREPEND(qmgr_transport_list, transport, peers);
-    if (msg_verbose)
-       msg_info("qmgr_transport_create: %s concurrency %d recipients %d",
-                transport->name, transport->dest_concurrency_limit,
-                transport->recipient_limit);
-    return (transport);
-}
-
-/* qmgr_transport_find - find transport instance */
-
-QMGR_TRANSPORT *qmgr_transport_find(const char *name)
-{
-    return ((QMGR_TRANSPORT *) htable_find(qmgr_transport_byname, name));
-}
index 0f4394e9d3dde27314cba7ed2ad31b26dd7a70e5..4a65146b0ef5d3c0a038eb5a1a31e4e1552b8156 100644 (file)
 #include <rec_type.h>
 #include <off_cvt.h>
 #include <mark_corrupt.h>
+#include <quote_821_local.h>
 
 /* Application-specific. */
 
 #include "smtp.h"
-#include "quote_821_local.h"
 #include "smtp_sasl.h"
 
  /*
index 0085bda697e76c77aa38ff1a4297a75aa703312a..d9128f1f52bddc850ce61d6ac82a6c81eb68c28f 100644 (file)
@@ -133,7 +133,7 @@ static void smtp_check_code(SMTP_STATE *state, int code)
      * anti-UCE systems, by people who aren't aware of RFC details.
      */
     if ((!SMTP_SOFT(code) && !SMTP_HARD(code))
-       || code == 555                          /* RFC 1869, section 6.1. */
+       || code == 555                  /* RFC 1869, section 6.1. */
        || (code >= 500 && code < 510))
        state->error_mask |= MAIL_ERROR_PROTOCOL;
 }
index 6f4703ed4642070354edc2b2f2dc271d27260a7d..9df7131819de1b7f04f4419b371f87e5fe860bc0 100644 (file)
 /* .IP \fBstrict_rfc821_envelopes\fR
 /*     Disallow non-RFC 821 style addresses in envelopes. For example,
 /*     allow RFC822-style address forms with comments, like Sendmail does.
+/* .IP \fBallow_broken_auth_clients\fR
+/*     Support older Microsoft clients that mis-implement the AUTH
+/*      protocol, and that expect an EHLO response of "250 AUTH=list"
+/*     instead of "250 AUTH list".
 /* .SH "Content inspection controls"
 /* .IP \fBcontent_filter\fR
 /*     The name of a mail delivery transport that filters mail and that
@@ -343,6 +347,7 @@ bool    var_smtpd_sasl_enable;
 char   *var_smtpd_sasl_opts;
 char   *var_smtpd_sasl_realm;
 char   *var_filter_xport;
+bool    var_broken_auth_clients;
 
  /*
   * Global state, for stand-alone mode queue file cleanup. When this is
@@ -439,8 +444,11 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "250-SIZE");
     smtpd_chat_reply(state, "250-ETRN");
 #ifdef USE_SASL_AUTH
-    if (var_smtpd_sasl_enable)
+    if (var_smtpd_sasl_enable) {
        smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
+       if (var_broken_auth_clients)
+           smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
+    }
 #endif
     smtpd_chat_reply(state, "250 8BITMIME");
     return (0);
@@ -949,7 +957,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        state->error_mask |= MAIL_ERROR_BOUNCE;
        smtpd_chat_reply(state, "554 Error: too many hops");
     } else if ((state->err & CLEANUP_STAT_CONT) != 0) {
-       state->error_mask |= MAIL_ERROR_BOUNCE;
+       state->error_mask |= MAIL_ERROR_POLICY;
        smtpd_chat_reply(state, "552 Error: content rejected");
     } else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
        state->error_mask |= MAIL_ERROR_RESOURCE;
@@ -1447,6 +1455,7 @@ int     main(int argc, char **argv)
        VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd,
        VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
        VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable,
+       VAR_BROKEN_AUTH_CLNTS, DEF_BROKEN_AUTH_CLNTS, &var_broken_auth_clients,
        0,
     };
     static CONFIG_STR_TABLE str_table[] = {
index a10b48e8eada370d3d77eece1dd87dac605cab3e..a4180135440505bfaf4745eedff85e1380f4c503 100644 (file)
@@ -329,12 +329,19 @@ static void disconnect(SINK_STATE *state)
 static void connect_event(int unused_event, char *context)
 {
     int     sock = CAST_CHAR_PTR_TO_INT(context);
+    struct sockaddr sa;
+    SOCKADDR_SIZE len = sizeof(sa);
     SINK_STATE *state;
     int     fd;
 
-    if ((fd = accept(sock, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) >= 0) {
+    if ((fd = accept(sock, &sa, &len)) >= 0) {
        if (msg_verbose)
-           msg_info("connect");
+           msg_info("connect (%s)", sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
+#ifdef AF_INET6
+                    sa.sa_family == AF_INET6 ? "AF_INET6" :
+#endif
+                    sa.sa_family == AF_INET ? "AF_INET" :
+                    "unknown protocol family");
        non_blocking(fd, NON_BLOCKING);
        state = (SINK_STATE *) mymalloc(sizeof(*state));
        state->stream = vstream_fdopen(fd, O_RDWR);
index c5d9dbcc7c24ab30f71ddde039d0b3d9edb84eb3..6ab916429bddbd409ab0ff27d63009812f6daf84 100644 (file)
@@ -136,10 +136,11 @@ static const char *var_myhostname;
 static int session_count;
 static int message_count = 1;
 static struct sockaddr_in sin;
+
 #undef sun
 static struct sockaddr_un sun;
 static struct sockaddr *sa;
-static int sa_len;
+static int sa_length;
 static int recipients = 1;
 static char *defaddr;
 static char *recipient;
@@ -398,7 +399,7 @@ static void start_connect(SESSION *session)
     session->stream = vstream_fdopen(fd, O_RDWR);
     event_enable_write(fd, connect_done, (char *) session);
     smtp_timeout_setup(session->stream, var_timeout);
-    if (connect(fd, sa, sa_len) < 0 && errno != EINPROGRESS)
+    if (connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
        fail_connect(session);
 }
 
@@ -842,7 +843,7 @@ int     main(int argc, char **argv)
 #endif
        memcpy(sun.sun_path, path, path_len);
        sa = (struct sockaddr *) & sun;
-       sa_len = sizeof(sun);
+       sa_length = sizeof(sun);
     } else {
        if (strncmp(argv[optind], "inet:", 5) == 0)
            argv[optind] += 5;
@@ -853,7 +854,7 @@ int     main(int argc, char **argv)
        sin.sin_addr.s_addr = find_inet_addr(host);
        sin.sin_port = find_inet_port(port, "tcp");
        sa = (struct sockaddr *) & sin;
-       sa_len = sizeof(sin);
+       sa_length = sizeof(sin);
     }
 
     /*
index 1ca68af132fac69832c1c2267d50e28f47133115..b3efcddbf6061d1b092051edfff2c62ead7d83d7 100644 (file)
@@ -81,8 +81,18 @@ int     make_dirs(const char *path, int perms)
        } else {
            if (errno != ENOENT)
                break;
-           if ((ret = mkdir(saved_path, perms)) < 0 && errno != EEXIST)
-               break;
+           if ((ret = mkdir(saved_path, perms)) < 0) {
+               if (errno != EEXIST)
+                   break;
+               /* Race condition? */
+               if ((ret = stat(saved_path, &st)) < 0) 
+                   break;
+               if (!S_ISDIR(st.st_mode)) {
+                   errno = ENOTDIR;
+                   ret = -1;
+                   break;
+               }
+           }
        }
        if (saved_ch != 0)
            *cp = saved_ch;
diff --git a/postfix/src/virtual/virtual b/postfix/src/virtual/virtual
new file mode 100755 (executable)
index 0000000..bde19ec
Binary files /dev/null and b/postfix/src/virtual/virtual differ