]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
snapshot-20000129
authorWietse Venema <wietse@porcupine.org>
Sat, 29 Jan 2000 00:00:00 +0000 (00:00 +0000)
committerWietse Venema <wietse@porcupine.org>
Thu, 17 Jan 2013 23:10:05 +0000 (18:10 -0500)
59 files changed:
postfix/HISTORY
postfix/INSTALL.sh
postfix/RELEASE_NOTES
postfix/bounce/Makefile.in
postfix/bounce/bounce.c
postfix/bounce/bounce_notify_service.c
postfix/bounce/bounce_recip_service.c [new file with mode: 0644]
postfix/bounce/bounce_service.h
postfix/cleanup/Makefile.in
postfix/cleanup/cleanup.c
postfix/cleanup/cleanup.h
postfix/cleanup/cleanup_api.c [new file with mode: 0644]
postfix/cleanup/cleanup_envelope.c
postfix/cleanup/cleanup_extracted.c
postfix/cleanup/cleanup_map11.c
postfix/cleanup/cleanup_map1n.c
postfix/cleanup/cleanup_message.c
postfix/cleanup/cleanup_out.c
postfix/cleanup/cleanup_out_recipient.c
postfix/cleanup/cleanup_skip.c [deleted file]
postfix/cleanup/cleanup_state.c
postfix/conf/main.cf
postfix/conf/pcre_table [new file with mode: 0644]
postfix/conf/regexp_table [new file with mode: 0644]
postfix/conf/sample-local.cf
postfix/global/bounce.c
postfix/global/bounce.h
postfix/global/cleanup_strerror.c
postfix/global/cleanup_user.h
postfix/global/defer.c
postfix/global/mail_params.h
postfix/global/mail_queue.c
postfix/global/mail_version.h
postfix/html/Makefile.in
postfix/html/access.5.html
postfix/html/faq.html
postfix/html/qmgr.8.html
postfix/html/smtp.8.html
postfix/local/maildir.c
postfix/makedefs
postfix/man/Makefile.in
postfix/man/man5/access.5
postfix/man/man8/qmgr.8
postfix/man/man8/smtp.8
postfix/master/master_sig.c
postfix/postconf/local_table.h
postfix/postconf/local_vars.h
postfix/qmgr/qmgr.c
postfix/qmgr/qmgr_message.c
postfix/smtp/smtp_trouble.c
postfix/smtpd/smtpd.c
postfix/smtpd/smtpd_check.c
postfix/util/Makefile.in
postfix/util/make_dirs.c
postfix/util/safe_open.c
postfix/util/sane_fsops.h [new file with mode: 0644]
postfix/util/sane_link.c [new file with mode: 0644]
postfix/util/sane_rename.c [new file with mode: 0644]
postfix/util/sys_defs.h

index b2ede1bab6af26bbc2a32311602e3f051cd62b31..9fae0c9d468b68a681b6370fa1b566510d3ba5d0 100644 (file)
@@ -3543,3 +3543,72 @@ Apologies for any names omitted.
 
        Portability: Siemens Pyramid (dcosx) patch by Thomas D.
        Knox @ vushta.com.
+
+       Performance: FreeBSD has bidirectional pipes that are faster
+       than socketpairs. Anticpiating on more platform-specific
+       optimizations, all duplex pipe plumbing is now isolated in
+       a duplex_pipe.c module that provides a system-independent
+       interface.
+
+20000105
+
+       Cleanup: the INSTALL.sh script now updates the sample files
+       in /etc/postfix even when main.cf exists.
+
+20000106
+
+       Bugfix: the SMTP server should consult the relocated map
+       for virtual destinations (Denis Shaposhnikov). Files:
+       smtpd/smtpd.c smtpd/smtpd_check.c.
+
+20000108
+
+       Workaround: rename() over NFS can fail with ENOENT even
+       when the operation succeeds (Graham Orndorff @ WebTV). This
+       is not news. Any non-idempotent operation can fail over
+       NFS when the NFS server's acknowledgement is lost and the
+       NFS client code retries the operation (other examples are:
+       create, symlink, link, unlink, mkdir, rmdir).  Postfix has
+       workarounds for the cases where this is most likely to
+       cause trouble. Files:  util/sane_{rename,link}.[hc].  If
+       you want reliable mail system, do not use NFS.
+
+20000115
+
+       Workaround: better detection of bad hardware. Added SIGBUS
+       to the list of signals that the master will log before
+       exiting.
+
+20000122
+
+       Portability: preliminary SCO5 port Christopher Wong @
+       csports.com. This still needs to a workaround for "find"
+       not supporting "-type s" (actually, UNIX-domain sockets
+       have no unique representation in the file system and show
+       up as FIFOs).
+
+20000115-22
+
+       Bugfix: in case of a too long message header, don't extract
+       recipients from message headers.  With the previous behavior,
+       Bcc information could be left in the message body, as one
+       person found out the hard way.  Files:  cleanup/cleanup.c,
+       cleanup/cleanup_extracted.c, global/cleanup_user.h.
+
+20000124
+
+       Whatever: RFC 1869 amends RFC 821 and specifies that code
+       555 is to be used when a MAIL FROM or RCPT TO parameter is
+       not implemented or not recognized. Russ Allbery @stanford.edu.
+       This reply code is added to the list of reply codes that
+       cause the Postfix SMTP client to mail a transcript to the
+       postmaster.  File: smtp/smtp_trouble.c.
+
+20000126
+
+       Emergency feature: qmgr_site_hog_factor (default: 90 percent)
+       limits the amount of resources that Postfix will devote to
+       a single site. With less than 100, Postfix will defer the
+       excess mail so that one site with a large backlog does not
+       block other deliveries.
+
index d6a82f21fd1cecd61c42f3e85c9469213c34e355..a2678419a927ff020c497dabb5c31bf2fd77aa40 100644 (file)
@@ -255,9 +255,13 @@ test -f bin/sendmail && {
     compare_or_symlink $SENDMAIL_PATH $MAILQ_PATH
 }
 
-compare_or_replace a+r,go-w conf/LICENSE $CONFIG_DIRECTORY/LICENSE || exit 1
-
-test -f $CONFIG_DIRECTORY/main.cf || {
+if [ -f $CONFIG_DIRECTORY/main.cf ]
+then
+    for file in LICENSE `cd conf; echo sample*` main.cf.default
+    do
+       compare_or_replace a+r,go-w conf/$file $CONFIG_DIRECTORY/$file || exit 1
+    done
+else
     cp conf/* $CONFIG_DIRECTORY || exit 1
     chmod a+r,go-w $CONFIG_DIRECTORY/* || exit 1
 
@@ -269,7 +273,7 @@ test -f $CONFIG_DIRECTORY/main.cf || {
        echo "BTW: Edit your alias database and be sure to set up aliases" 1>&2
        echo "for root and postmaster, then run $NEWALIASES_PATH." 1>&2
     }
-}
+fi
 
 # Save settings.
 
index 29ee8f20be38eb9f31269f8e94239278a283e716..506e100dccd666b405f2963cf1ffda15072b4c5b 100644 (file)
@@ -88,9 +88,9 @@ installation can be done without write access to the build tree.
 domains that are defined by Postfix virtual maps.
 
 - The SMTP server can reject mail for unknown local users.  Specify
-"local_recipient_maps = $relocated_maps, $alias_maps, unix:passwd.byname"
-if your local mail is delivered by a UNIX-style local delivery
-agent.  See example in conf/main.cf.
+"local_recipient_maps = $alias_maps, unix:passwd.byname" if your
+local mail is delivered by a UNIX-style local delivery agent.  See
+example in conf/main.cf.
 
 - Use "disable_vrfy_command = yes" to disable the SMTP VRFY command.
 This prevents some forms of address harvesting.
index f2070a7ce4eac1f50671185bb654a9bba78d60d4..44d5b7ed2841607f6826383457c4e3aa401f6aef 100644 (file)
@@ -1,8 +1,8 @@
 SHELL  = /bin/sh
 SRCS   = bounce.c bounce_append_service.c bounce_notify_service.c \
-       bounce_cleanup.c
+       bounce_recip_service.c bounce_cleanup.c
 OBJS   = bounce.o bounce_append_service.o bounce_notify_service.o \
-       bounce_cleanup.o
+       bounce_recip_service.o bounce_cleanup.o
 HDRS   = 
 TESTSRC        = 
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -119,3 +119,31 @@ bounce_notify_service.o: ../include/mail_addr.h
 bounce_notify_service.o: ../include/mark_corrupt.h
 bounce_notify_service.o: ../include/mail_error.h
 bounce_notify_service.o: bounce_service.h
+bounce_recip_service.o: bounce_recip_service.c
+bounce_recip_service.o: ../include/sys_defs.h
+bounce_recip_service.o: ../include/msg.h
+bounce_recip_service.o: ../include/vstring.h
+bounce_recip_service.o: ../include/vbuf.h
+bounce_recip_service.o: ../include/vstream.h
+bounce_recip_service.o: ../include/vstring_vstream.h
+bounce_recip_service.o: ../include/mymalloc.h
+bounce_recip_service.o: ../include/stringops.h
+bounce_recip_service.o: ../include/events.h
+bounce_recip_service.o: ../include/line_wrap.h
+bounce_recip_service.o: ../include/name_mask.h
+bounce_recip_service.o: ../include/mail_queue.h
+bounce_recip_service.o: ../include/mail_proto.h
+bounce_recip_service.o: ../include/iostuff.h
+bounce_recip_service.o: ../include/quote_822_local.h
+bounce_recip_service.o: ../include/mail_params.h
+bounce_recip_service.o: ../include/canon_addr.h
+bounce_recip_service.o: ../include/is_header.h
+bounce_recip_service.o: ../include/record.h
+bounce_recip_service.o: ../include/rec_type.h
+bounce_recip_service.o: ../include/mail_conf.h
+bounce_recip_service.o: ../include/post_mail.h
+bounce_recip_service.o: ../include/cleanup_user.h
+bounce_recip_service.o: ../include/mail_addr.h
+bounce_recip_service.o: ../include/mark_corrupt.h
+bounce_recip_service.o: ../include/mail_error.h
+bounce_recip_service.o: bounce_service.h
index 63a46e3fc0981fffff61ec3850da93cd2e564ddf..616527fbdf671f5e56d0f3f8f3a386c42fb6cdc5 100644 (file)
@@ -21,6 +21,8 @@
 /*     Post a bounce message, with a copy of a log file and of the
 /*     corresponding message. When the bounce is posted successfully,
 /*     the log file is deleted.
+/* .IP \(bu
+/*     Post a bounce message without accessing a per-message log file.
 /* .PP
 /*     The software does a best effort to notify the sender that there
 /*     was a problem. A notification is sent even when the log file
@@ -198,7 +200,42 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush)
      * Execute the request.
      */
     return (bounce_notify_service(service_name, STR(queue_name),
-                                STR(queue_id), STR(sender), flush));
+                                 STR(queue_id), STR(sender), flush));
+}
+
+/* bounce_recip_proto - bounce_recip server protocol */
+
+static int bounce_recip_proto(char *service_name, VSTREAM *client, int flush)
+{
+    int     flags;
+
+    /*
+     * Read and validate the client request.
+     */
+    if (mail_command_read(client, "%d %s %s %s %s %s",
+                         &flags, queue_name, queue_id,
+                         sender, recipient, why) != 6) {
+       msg_warn("malformed request");
+       return (-1);
+    }
+    if (mail_queue_name_ok(STR(queue_name)) == 0) {
+       msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
+       return (-1);
+    }
+    if (mail_queue_id_ok(STR(queue_id)) == 0) {
+       msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
+       return (-1);
+    }
+    if (msg_verbose)
+       msg_info("bounce_recip_proto: service=%s queue=%s id=%s sender=%s recip=%s why=%s",
+                service_name, STR(queue_name), STR(queue_id),
+                STR(sender), STR(recipient), STR(why));
+
+    /*
+     * Execute the request.
+     */
+    return (bounce_recip_service(service_name, STR(queue_name), STR(queue_id),
+                            STR(sender), STR(recipient), STR(why), flush));
 }
 
 /* bounce_service - parse bounce command type and delegate */
@@ -233,6 +270,8 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv)
        status = bounce_notify_proto(service_name, client, JUST_WARN);
     } else if (command == BOUNCE_CMD_APPEND) {
        status = bounce_append_proto(service_name, client);
+    } else if (command == BOUNCE_CMD_RECIP) {
+       status = bounce_recip_proto(service_name, client, REALLY_BOUNCE);
     } else {
        msg_warn("unknown command: %d", command);
        status = -1;
index 53be2e8a6d4f549b7c090facd1b9be373e43dcf1..5ff5475b7ba12b42552e8c3eb216ddac1873e3f4 100644 (file)
@@ -361,7 +361,7 @@ int     bounce_notify_service(char *service, char *queue_name,
 #define BOUNCE_ALL             0
 
     /*
-     * The choice of sender address depends on recipient the address. For a
+     * The choice of sender address depends on the recipient address. For a
      * single bounce (a non-delivery notification to the message originator),
      * the sender address is the empty string. For a double bounce (typically
      * a failed single bounce, or a postmaster notification that was produced
diff --git a/postfix/bounce/bounce_recip_service.c b/postfix/bounce/bounce_recip_service.c
new file mode 100644 (file)
index 0000000..80af89a
--- /dev/null
@@ -0,0 +1,474 @@
+/*++
+/* NAME
+/*     bounce_recip_service 3
+/* SUMMARY
+/*     send non-delivery report to sender, server side
+/* SYNOPSIS
+/*     #include "bounce_service.h"
+/*
+/*     int     bounce_recip_service(queue_name, queue_id, sender,
+/*                                     bounced_addr, why, flush)
+/*     char    *queue_name;
+/*     char    *queue_id;
+/*     char    *sender;
+/*     char    *recipient;
+/*     char    *why;
+/*     int     flush;
+/* DESCRIPTION
+/*     This module implements the server side of the bounce_recip()
+/*     (send bounce message) request. If flush is zero, the logfile
+/*     is not removed, and a warning is sent instead of a bounce.
+/*
+/*     When a message bounces, a full copy is sent to the originator,
+/*     and an optional  copy of the diagnostics with message headers is
+/*     sent to the postmaster.  The result is non-zero when the operation
+/*     should be tried again.
+/*
+/*     When a bounce is sent, the sender address is the empty
+/*     address.  When a bounce bounces, an optional double bounce
+/*     with the entire undeliverable mail is sent to the postmaster,
+/*     with as sender address the double bounce address.
+/* DIAGNOSTICS
+/*     Fatal error: error opening existing file. Warnings: corrupt
+/*     message file. A corrupt message is saved to the "corrupt"
+/*     queue for further inspection.
+/* BUGS
+/* SEE ALSO
+/*     bounce(3) basic bounce service client interface
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <events.h>
+#include <line_wrap.h>
+#include <name_mask.h>
+
+/* Global library. */
+
+#include <mail_queue.h>
+#include <mail_proto.h>
+#include <quote_822_local.h>
+#include <mail_params.h>
+#include <canon_addr.h>
+#include <is_header.h>
+#include <record.h>
+#include <rec_type.h>
+#include <mail_conf.h>
+#include <post_mail.h>
+#include <mail_addr.h>
+#include <mark_corrupt.h>
+#include <mail_error.h>
+
+/* Application-specific. */
+
+#include "bounce_service.h"
+
+#define STR vstring_str
+
+/* bounce_header - generate bounce message header */
+
+static int bounce_header(VSTREAM *bounce, VSTRING *buf, const char *dest,
+                                const char *boundary, int flush)
+{
+
+    /*
+     * Print a minimal bounce header. The cleanup service will add other
+     * headers and will make all addresses fully qualified.
+     */
+#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
+
+    post_mail_fprintf(bounce, "From: %s (Mail Delivery System)",
+                     MAIL_ADDR_MAIL_DAEMON);
+
+    if (flush) {
+       post_mail_fputs(bounce, dest == var_bounce_rcpt
+                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
+                       "Subject: Postmaster Copy: Undelivered Mail" :
+                       "Subject: Undelivered Mail Returned to Sender");
+    } else {
+       post_mail_fputs(bounce, dest == var_bounce_rcpt
+                    || dest == var_2bounce_rcpt || dest == var_delay_rcpt ?
+                       "Subject: Postmaster Warning: Delayed Mail" :
+                       "Subject: Delayed Mail (still being retried)");
+    }
+    post_mail_fprintf(bounce, "To: %s", STR(quote_822_local(buf, dest)));
+
+    /*
+     * MIME header.
+     */
+    post_mail_fprintf(bounce, "MIME-Version: 1.0");
+#ifdef DSN
+    post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
+                     "multipart/report", "delivery-status");
+#else
+    post_mail_fprintf(bounce, "Content-Type: multipart/mixed;");
+#endif
+    post_mail_fprintf(bounce, "\tboundary=\"%s\"", boundary);
+    post_mail_fputs(bounce, "");
+    post_mail_fputs(bounce, "This is a MIME-encapsulated message.");
+
+    /*
+     * More MIME header.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s", "Notification");
+    post_mail_fprintf(bounce, "Content-Type: %s", "text/plain");
+    post_mail_fputs(bounce, "");
+
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_boilerplate - generate boiler-plate text */
+
+static int bounce_boilerplate(VSTREAM *bounce, VSTRING *buf,
+                                     const char *boundary, int flush)
+{
+
+    /*
+     * Print the message body with the problem report. XXX For now, we use a
+     * fixed bounce template. We could use a site-specific parametrized
+     * template with ${name} macros and we could do wonderful things such as
+     * word wrapping to make the text look nicer. No matter how hard we would
+     * try, receiving bounced mail will always suck.
+     */
+    post_mail_fprintf(bounce, "This is the %s program at host %s.",
+                     var_mail_name, var_myhostname);
+    post_mail_fputs(bounce, "");
+    if (flush) {
+       post_mail_fputs(bounce,
+              "I'm sorry to have to inform you that the message returned");
+       post_mail_fputs(bounce,
+              "below could not be delivered to one or more destinations.");
+    } else {
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce,
+                       "# THIS IS A WARNING ONLY.  YOU DO NOT NEED TO RESEND YOUR MESSAGE. #");
+       post_mail_fputs(bounce,
+                       "####################################################################");
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+                       "Your message could not be delivered for %d hours.",
+                         var_delay_warn_time);
+       post_mail_fprintf(bounce,
+                         "It will be retried until it is %d days old.",
+                         var_max_queue_time);
+    }
+
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce,
+                     "For further assistance, please contact <%s>",
+                     STR(canon_addr_external(buf, MAIL_ADDR_POSTMASTER)));
+    if (flush) {
+       post_mail_fputs(bounce, "");
+       post_mail_fprintf(bounce,
+              "If you do so, please include this problem report. You can");
+       post_mail_fprintf(bounce,
+                  "delete your own text from the message returned below.");
+    }
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "\t\t\tThe %s program", var_mail_name);
+    post_mail_fputs(bounce, "");
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_print - line_wrap callback */
+
+static void bounce_print(const char *str, int len, int indent, char *context)
+{
+    VSTREAM *bounce = (VSTREAM *) context;
+
+    post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
+}
+
+/* bounce_diagnostics - send bounce log report */
+
+static int bounce_diagnostics(VSTREAM *bounce, const char *boundary,
+                                   const char *unused_recipient, char *why)
+{
+
+    /*
+     * MIME header.
+     */
+#ifdef DSN
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s", "Delivery error report");
+    post_mail_fprintf(bounce, "Content-Type: %s", "message/delivery-status");
+    post_mail_fputs(bounce, "");
+#endif
+
+    /*
+     * Append a copy of the delivery error log. Again, we're doing a best
+     * effort, so there is no point raising a fatal run-time error in case of
+     * a logfile read error. Wrap long lines, filter non-printable
+     * characters, and prepend one blank, so this data can safely be piped
+     * into other programs.
+     * 
+     * XXX recipient may be empty.
+     */
+
+#define LENGTH 79
+#define INDENT 4
+    printable(why, '_');
+    line_wrap(why, LENGTH, INDENT, bounce_print, (char *) bounce);
+    return (vstream_ferror(bounce));
+}
+
+/* bounce_original - send a copy of the original to the victim */
+
+static int bounce_original(char *service, VSTREAM *bounce, VSTRING *buf,
+                                  char *queue_name, char *queue_id,
+                                  const char *boundary, int headers_only)
+{
+    int     status = 0;
+    VSTREAM *src;
+    int     rec_type;
+    int     bounce_length;
+
+    /*
+     * MIME headers.
+     */
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s", boundary);
+    post_mail_fprintf(bounce, "Content-Description: %s", "Undelivered Message");
+    post_mail_fprintf(bounce, "Content-Type: %s", headers_only ?
+                     "text/rfc822-headers" : "message/rfc822");
+    post_mail_fputs(bounce, "");
+
+    /*
+     * If the original message cannot be found, do not raise a run-time
+     * error. There is nothing we can do about the error, and all we are
+     * doing is to inform the sender of a delivery problem. Bouncing a
+     * message does not have to be a perfect job. But if the system IS
+     * running out of resources, raise a fatal run-time error and force a
+     * backoff.
+     */
+    if ((src = mail_queue_open(queue_name, queue_id, O_RDONLY, 0)) == 0) {
+       if (errno != ENOENT)
+           msg_fatal("open %s %s: %m", service, queue_id);
+       post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
+       post_mail_fputs(bounce, "");
+       return (vstream_ferror(bounce));
+    }
+
+    /*
+     * Skip over the original message envelope records. If the envelope is
+     * corrupted just send whatever we can (remember this is a best effort,
+     * it does not have to be perfect).
+     */
+    while ((rec_type = rec_get(src, buf, 0)) > 0)
+       if (rec_type == REC_TYPE_MESG)
+           break;
+
+    /*
+     * Copy the original message contents. Limit the amount of bounced text
+     * so there is a better chance of the bounce making it back. We're doing
+     * raw record output here so that we don't throw away binary transparency
+     * yet.
+     */
+#define IS_HEADER(s) (ISSPACE(*(s)) || is_header(s))
+
+    bounce_length = 0;
+    while (status == 0 && (rec_type = rec_get(src, buf, 0)) > 0) {
+       if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
+           break;
+       if (headers_only && !IS_HEADER(vstring_str(buf)))
+           break;
+       if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) {
+           bounce_length += VSTRING_LEN(buf);
+           status = (REC_PUT_BUF(bounce, rec_type, buf) != rec_type);
+       }
+    }
+    post_mail_fputs(bounce, "");
+    post_mail_fprintf(bounce, "--%s--", boundary);
+    if (headers_only == 0 && rec_type != REC_TYPE_XTRA)
+       status |= mark_corrupt(src);
+    if (vstream_fclose(src))
+       msg_warn("read message file %s %s: %m", queue_name, queue_id);
+    return (status);
+}
+
+/* bounce_recip_service - send a bounce */
+
+int     bounce_recip_service(char *service, char *queue_name, char *queue_id,
+                                    char *recipient, char *bounced_addr,
+                                    char *why, int flush)
+{
+    VSTRING *buf = vstring_alloc(100);
+    int     bounce_status = 1;
+    int     postmaster_status = 1;
+    VSTREAM *bounce;
+    int     notify_mask = name_mask(mail_error_masks, var_notify_classes);
+    VSTRING *boundary = vstring_alloc(100);
+    char   *postmaster;
+
+    /*
+     * Unique string for multi-part message boundaries.
+     */
+    vstring_sprintf(boundary, "%s.%ld/%s",
+                   queue_id, event_time(), var_myhostname);
+
+#define NULL_SENDER            MAIL_ADDR_EMPTY /* special address */
+#define NULL_CLEANUP_FLAGS     0
+#define BOUNCE_HEADERS         1
+#define BOUNCE_ALL             0
+
+    /*
+     * The choice of sender address depends on the recipient address. For a
+     * single bounce (a non-delivery notification to the message originator),
+     * the sender address is the empty string. For a double bounce (typically
+     * a failed single bounce, or a postmaster notification that was produced
+     * by any of the mail processes) the sender address is defined by the
+     * var_double_bounce_sender configuration variable. When a double bounce
+     * cannot be delivered, the queue manager blackholes the resulting triple
+     * bounce message.
+     */
+
+    /*
+     * Double bounce failed. Never send a triple bounce.
+     * 
+     * However, this does not prevent double bounces from bouncing on other
+     * systems. In order to cope with this, either the queue manager must
+     * recognize the double-bounce recipient address and discard mail, or
+     * every delivery agent must recognize the double-bounce sender address
+     * and substitute something else so mail does not come back at us.
+     */
+    if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) {
+       msg_warn("%s: undeliverable postmaster notification discarded",
+                queue_id);
+       bounce_status = 0;
+    }
+
+    /*
+     * Single bounce failed. Optionally send a double bounce to postmaster.
+     */
+#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
+#define SKIP_IF_BOUNCE (flush == 1 && (notify_mask & ANY_BOUNCE) == 0)
+#define SKIP_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY) == 0)
+
+    else if (*recipient == 0) {
+       if (SKIP_IF_BOUNCE || SKIP_IF_DELAY) {
+           bounce_status = 0;
+       } else {
+           postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                postmaster,
+                                                NULL_CLEANUP_FLAGS,
+                                                "BOUNCE")) != 0) {
+
+               /*
+                * Double bounce to Postmaster. This is the last opportunity
+                * for this message to be delivered. Send the text with
+                * reason for the bounce, and the headers of the original
+                * message. Don't bother sending the boiler-plate text.
+                */
+               if (!bounce_header(bounce, buf, postmaster,
+                                  STR(boundary), flush)
+                   && bounce_diagnostics(bounce, STR(boundary),
+                                         bounced_addr, why) == 0)
+                   bounce_original(service, bounce, buf, queue_name, queue_id,
+                                   STR(boundary),
+                                   flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+               bounce_status = post_mail_fclose(bounce);
+           }
+       }
+    }
+
+    /*
+     * Non-bounce failed. Send a single bounce.
+     */
+    else {
+       if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
+                                            NULL_CLEANUP_FLAGS,
+                                            "BOUNCE")) != 0) {
+
+           /*
+            * Send the bounce message header, some boilerplate text that
+            * pretends that we are a polite mail system, the text with
+            * reason for the bounce, and a copy of the original message.
+            */
+           if (bounce_header(bounce, buf, recipient, STR(boundary), flush) == 0
+               && bounce_boilerplate(bounce, buf, STR(boundary), flush) == 0
+               && bounce_diagnostics(bounce, STR(boundary),
+                                     bounced_addr, why) == 0)
+               bounce_original(service, bounce, buf, queue_name, queue_id,
+                               STR(boundary),
+                               flush ? BOUNCE_ALL : BOUNCE_HEADERS);
+           bounce_status = post_mail_fclose(bounce);
+       }
+
+       /*
+        * Optionally, send a postmaster notice.
+        * 
+        * This postmaster notice is not critical, so if it fails don't
+        * retransmit the bounce that we just generated, just log a warning.
+        */
+#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE))
+#define WANT_IF_DELAY  (flush == 0 && (notify_mask & MAIL_ERROR_DELAY))
+
+       if (bounce_status == 0 && (WANT_IF_BOUNCE || WANT_IF_DELAY)
+           && strcasecmp(recipient, mail_addr_double_bounce()) != 0) {
+
+           /*
+            * Send the text with reason for the bounce, and the headers of
+            * the original message. Don't bother sending the boiler-plate
+            * text. This postmaster notice is not critical, so if it fails
+            * don't retransmit the bounce that we just generated, just log a
+            * warning.
+            */
+           postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
+           if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
+                                                postmaster,
+                                                NULL_CLEANUP_FLAGS,
+                                                "BOUNCE")) != 0) {
+               if (!bounce_header(bounce, buf, postmaster,
+                                  STR(boundary), flush)
+                   && bounce_diagnostics(bounce, STR(boundary),
+                                         bounced_addr, why) == 0)
+                   bounce_original(service, bounce, buf, queue_name, queue_id,
+                                   STR(boundary), BOUNCE_HEADERS);
+               postmaster_status = post_mail_fclose(bounce);
+           }
+           if (postmaster_status)
+               msg_warn("postmaster notice failed while bouncing to %s",
+                        recipient);
+       }
+    }
+
+    /*
+     * Cleanup.
+     */
+    vstring_free(buf);
+    vstring_free(boundary);
+
+    return (bounce_status);
+}
index 5385e550fcfe58fb38ff7c729cf8ae3c78370539..c298897078725d010f79553a7e131216fb10ca9a 100644 (file)
@@ -23,6 +23,11 @@ extern int bounce_append_service(char *, char *, char *, char *);
   */
 extern int bounce_notify_service(char *, char *, char *, char *, int);
 
+ /*
+  * bounce_recip_service.c
+  */
+extern int bounce_recip_service(char *, char *, char *, char *, char *, char *, int);
+
  /*
   * bounce_cleanup.c
   */
index 47bcbe6fe86df327b1b6f34df2f18465b4a58054..7185795f95b7093f7879e70b2e5a5d1ce7299878 100644 (file)
@@ -1,10 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = cleanup.c cleanup_out.c cleanup_envelope.c cleanup_message.c \
-       cleanup_extracted.c cleanup_state.c cleanup_skip.c cleanup_rewrite.c \
+       cleanup_extracted.c cleanup_state.c cleanup_api.c cleanup_rewrite.c \
        cleanup_map11.c cleanup_map1n.c cleanup_masquerade.c \
        cleanup_out_recipient.c
 OBJS   = cleanup.o cleanup_out.o cleanup_envelope.o cleanup_message.o \
-       cleanup_extracted.o cleanup_state.o cleanup_skip.o cleanup_rewrite.o \
+       cleanup_extracted.o cleanup_state.o cleanup_api.o cleanup_rewrite.o \
        cleanup_map11.o cleanup_map1n.o cleanup_masquerade.o \
        cleanup_out_recipient.o
 HDRS   =
@@ -80,12 +80,37 @@ cleanup.o: ../include/mail_params.h
 cleanup.o: ../include/mail_stream.h
 cleanup.o: ../include/mail_addr.h
 cleanup.o: ../include/ext_prop.h
+cleanup.o: ../include/record.h
+cleanup.o: ../include/rec_type.h
 cleanup.o: ../include/mail_server.h
 cleanup.o: cleanup.h
 cleanup.o: ../include/maps.h
 cleanup.o: ../include/tok822.h
 cleanup.o: ../include/resolve_clnt.h
 cleanup.o: ../include/been_here.h
+cleanup_api.o: cleanup_api.c
+cleanup_api.o: ../include/sys_defs.h
+cleanup_api.o: ../include/msg.h
+cleanup_api.o: ../include/vstring.h
+cleanup_api.o: ../include/vbuf.h
+cleanup_api.o: ../include/mymalloc.h
+cleanup_api.o: ../include/cleanup_user.h
+cleanup_api.o: ../include/mail_queue.h
+cleanup_api.o: ../include/vstream.h
+cleanup_api.o: ../include/mail_proto.h
+cleanup_api.o: ../include/iostuff.h
+cleanup_api.o: ../include/opened.h
+cleanup_api.o: ../include/bounce.h
+cleanup_api.o: ../include/mail_params.h
+cleanup_api.o: ../include/mail_stream.h
+cleanup_api.o: ../include/mail_addr.h
+cleanup_api.o: cleanup.h
+cleanup_api.o: ../include/argv.h
+cleanup_api.o: ../include/maps.h
+cleanup_api.o: ../include/dict.h
+cleanup_api.o: ../include/tok822.h
+cleanup_api.o: ../include/resolve_clnt.h
+cleanup_api.o: ../include/been_here.h
 cleanup_envelope.o: cleanup_envelope.c
 cleanup_envelope.o: ../include/sys_defs.h
 cleanup_envelope.o: ../include/msg.h
@@ -256,33 +281,16 @@ cleanup_rewrite.o: ../include/maps.h
 cleanup_rewrite.o: ../include/dict.h
 cleanup_rewrite.o: ../include/been_here.h
 cleanup_rewrite.o: ../include/mail_stream.h
-cleanup_skip.o: cleanup_skip.c
-cleanup_skip.o: ../include/sys_defs.h
-cleanup_skip.o: ../include/msg.h
-cleanup_skip.o: ../include/vstream.h
-cleanup_skip.o: ../include/vbuf.h
-cleanup_skip.o: ../include/cleanup_user.h
-cleanup_skip.o: ../include/record.h
-cleanup_skip.o: ../include/vstring.h
-cleanup_skip.o: ../include/rec_type.h
-cleanup_skip.o: cleanup.h
-cleanup_skip.o: ../include/argv.h
-cleanup_skip.o: ../include/maps.h
-cleanup_skip.o: ../include/dict.h
-cleanup_skip.o: ../include/tok822.h
-cleanup_skip.o: ../include/resolve_clnt.h
-cleanup_skip.o: ../include/been_here.h
-cleanup_skip.o: ../include/mail_stream.h
 cleanup_state.o: cleanup_state.c
 cleanup_state.o: ../include/sys_defs.h
 cleanup_state.o: ../include/mymalloc.h
 cleanup_state.o: ../include/vstring.h
 cleanup_state.o: ../include/vbuf.h
-cleanup_state.o: ../include/vstream.h
+cleanup_state.o: ../include/argv.h
 cleanup_state.o: ../include/been_here.h
 cleanup_state.o: ../include/mail_params.h
 cleanup_state.o: cleanup.h
-cleanup_state.o: ../include/argv.h
+cleanup_state.o: ../include/vstream.h
 cleanup_state.o: ../include/maps.h
 cleanup_state.o: ../include/dict.h
 cleanup_state.o: ../include/tok822.h
index f40e27751bd7437248af627e847fedaa0bcecaef..a1d89e9aba96ef35dab9a3f2efa06ba7b7aff75e 100644 (file)
 #include <mail_stream.h>
 #include <mail_addr.h>
 #include <ext_prop.h>
+#include <record.h>
+#include <rec_type.h>
 
 /* Single-threaded server skeleton. */
 
 
 #include "cleanup.h"
 
- /*
-  * Global state: any queue files that we have open, so that the error
-  * handler can clean up in case of trouble.
-  */
-char   *cleanup_path;                  /* queue file name */
-
  /*
   * Tunable parameters.
   */
@@ -197,13 +193,10 @@ int     cleanup_ext_prop_mask;
 
 static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
 {
-    char   *junk;
-    static char *log_queues[] = {
-       MAIL_QUEUE_DEFER,
-       MAIL_QUEUE_BOUNCE,
-       0,
-    };
-    char  **cpp;
+    VSTRING *buf = vstring_alloc(100);
+    CLEANUP_STATE *state;
+    int     flags;
+    int     type;
 
     /*
      * Sanity check. This service takes no command-line arguments.
@@ -212,166 +205,60 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
        msg_fatal("unexpected command-line argument: %s", argv[0]);
 
     /*
-     * Initialize.
-     */
-    cleanup_state_alloc();
-    cleanup_src = src;
-
-    /*
-     * Open the queue file. Send the queue ID to the client so they can use
-     * it for logging purposes. For example, the SMTP server sends the queue
-     * id to the SMTP client after completion of the DATA command; and when
-     * the local delivery agent forwards a message, it logs the new queue id
-     * together with the old one. All this is done to make it easier for mail
-     * admins to follow a message while it hops from machine to machine.
-     * 
-     * Save the queue file name, so that the runtime error handler can clean up
-     * in case of problems.
+     * Open a queue file and initialize state.
      */
-    cleanup_handle = mail_stream_file(MAIL_QUEUE_INCOMING,
-                                     MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE);
-    cleanup_dst = cleanup_handle->stream;
-    cleanup_path = mystrdup(VSTREAM_PATH(cleanup_dst));
-    cleanup_queue_id = mystrdup(cleanup_handle->id);
-    if (msg_verbose)
-       msg_info("cleanup_service: open %s", cleanup_path);
-
-    /*
-     * If there is a time to get rid of spurious bounce/defer log files, this
-     * is it. The down side is that this costs performance for every message,
-     * while the probability of spurious bounce/defer log files is quite low.
-     * Perhaps we should put the queue file ID inside the defer and bounce
-     * files, so that the bounce and defer daemons can figure out if a file
-     * is a left-over from a previous message instance. For now, we play safe
-     * and check each time a new queue file is created.
-     */
-    for (cpp = log_queues; *cpp; cpp++) {
-       if (mail_queue_remove(*cpp, cleanup_queue_id) == 0)
-           msg_warn("%s: removed spurious %s log", *cpp, cleanup_queue_id);
-       else if (errno != ENOENT)
-           msg_fatal("%s: remove %s log: %m", *cpp, cleanup_queue_id);
-    }
+    state = cleanup_open();
 
     /*
      * Send the queue id to the client. Read client processing options. If we
      * can't read the client processing options we can pretty much forget
      * about the whole operation.
      */
-    mail_print(cleanup_src, "%s", cleanup_queue_id);
-    if (mail_scan(src, "%d", &cleanup_flags) != 1) {
-       cleanup_errs |= CLEANUP_STAT_BAD;
-       cleanup_flags = 0;
-    }
-
-    /*
-     * If the client requests us to do the bouncing in case of problems,
-     * throw away the input only in case of real show-stopper errors, such as
-     * unrecognizable data (which should never happen) or insufficient space
-     * for the queue file (which will happen occasionally). Otherwise, throw
-     * away the input after any error. See the CLEANUP_OUT_OK() definition.
-     */
-    if (cleanup_flags & CLEANUP_FLAG_BOUNCE) {
-       cleanup_err_mask =
-           (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE | CLEANUP_STAT_SIZE);
-    } else {
-       cleanup_err_mask = ~0;
+    mail_print(src, "%s", state->queue_id);
+    if (mail_scan(src, "%d", &flags) != 1) {
+       state->errs |= CLEANUP_STAT_BAD;
+       flags = 0;
     }
+    cleanup_control(state, flags);
 
     /*
+     * XXX Rely on the front-end programs to enforce record size limits.
+     * 
      * First, copy the envelope records to the queue file. Then, copy the
      * message content (headers and body). Finally, attach any information
      * extracted from message headers.
      */
-    cleanup_envelope();
-    if (CLEANUP_OUT_OK())
-       cleanup_message();
-    if (CLEANUP_OUT_OK())
-       cleanup_extracted();
-
-    /*
-     * Now that we have captured the entire message, see if there are any
-     * other errors. For example, if the message needs to be bounced for lack
-     * of recipients. We want to turn on the execute bits on a file only when
-     * we want the queue manager to process it.
-     */
-    if (cleanup_recip == 0)
-       cleanup_errs |= CLEANUP_STAT_RCPT;
-
-    /*
-     * If there are no errors, be very picky about queue file write errors
-     * because we are about to tell the sender that it can throw away its
-     * copy of the message.
-     */
-    if (cleanup_errs == 0)
-       cleanup_errs |= mail_stream_finish(cleanup_handle);
-    else
-       mail_stream_cleanup(cleanup_handle);
-    cleanup_handle = 0;
-    cleanup_dst = 0;
+    while (CLEANUP_OUT_OK(state)) {
+       if ((type = rec_get(src, buf, 0)) < 0) {
+           state->errs |= CLEANUP_STAT_BAD;
+           break;
+       }
+       CLEANUP_RECORD(state, type, vstring_str(buf), VSTRING_LEN(buf));
+       if (type == REC_TYPE_END)
+           break;
+    }
 
     /*
-     * If there was an error, remove the queue file, after optionally
-     * bouncing it. An incomplete message should never be bounced: it was
-     * canceled by the client, and may not even have an address to bounce to.
-     * That last test is redundant but we keep it just for robustness.
-     * 
-     * If we are responsible for bouncing a message, we must must report success
-     * to the client unless the bounce message file could not be written
-     * (which is just as bad as not being able to write the message queue
-     * file in the first place).
-     * 
-     * Do not log the arrival of a message that will be bounced by the client.
+     * Keep reading in case of problems, so that the sender is ready to
+     * receive our status report.
      */
-#define CAN_BOUNCE() \
-       ((cleanup_errs & (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE)) == 0 \
-           && cleanup_sender != 0 \
-           && (cleanup_flags & CLEANUP_FLAG_BOUNCE) != 0)
-
-    if (cleanup_errs) {
-       if (CAN_BOUNCE()) {
-           if (bounce_append(BOUNCE_FLAG_CLEAN,
-                             cleanup_queue_id, cleanup_recip ?
-                             cleanup_recip : "", "cleanup", cleanup_time,
-                             "%s", cleanup_strerror(cleanup_errs)) == 0
-               && bounce_flush(BOUNCE_FLAG_CLEAN,
-                               MAIL_QUEUE_INCOMING,
-                               cleanup_queue_id, cleanup_sender) == 0) {
-               cleanup_errs = 0;
-           } else {
-               msg_warn("%s: bounce message failure", cleanup_queue_id);
-               cleanup_errs = CLEANUP_STAT_WRITE;
-           }
-       }
-       if (REMOVE(cleanup_path))
-           msg_warn("remove %s: %m", cleanup_path);
+    if (CLEANUP_OUT_OK(state) == 0) {
+       if ((state->errs & CLEANUP_STAT_CONT) == 0)
+           msg_warn("%s: skipping further client input", state->queue_id);
+       while ((type = rec_get(src, buf, 0)) > 0
+              && type != REC_TYPE_END)
+            /* void */ ;
     }
 
     /*
-     * Report the completion status back to the client. Order of operations
-     * matters very much: make sure that our queue file will not be deleted
-     * by the error handler AFTER we have taken responsibility for delivery.
-     * Better to deliver twice than to lose mail.
+     * Finish this message, and report the result status to the client.
      */
-    junk = cleanup_path;
-    cleanup_path = 0;                          /* don't delete upon error */
-    mail_print(cleanup_src, "%d", cleanup_errs);/* we're committed now */
-    if (msg_verbose)
-       msg_info("cleanup_service: status %d", cleanup_errs);
-    myfree(junk);
+    mail_print(src, "%d", cleanup_close(state));/* we're committed now */
 
     /*
-     * Cleanup internal state. This is simply complementary to the
-     * initializations at the beginning of this routine.
+     * Cleanup.
      */
-    cleanup_state_free();
-}
-
-/* cleanup_all - callback for the runtime error handler */
-
-static void cleanup_all(void)
-{
-    if (cleanup_path && REMOVE(cleanup_path))
-       msg_warn("cleanup_all: remove %s: %m", cleanup_path);
+    vstring_free(buf);
 }
 
 /* cleanup_sig - cleanup after signal */
index 69fc0142988eda94f86d3b1202b1810c2760d0f7..15d46981ead0bc89c940e0a3edc6c9ee0b16e868 100644 (file)
 
  /*
   * These state variables are accessed by many functions, and there is only
-  * one instance of each. Rather than passing around lots and lots of
-  * parameters, or passing them around as part of a huge structure, we just
-  * make the variables global, because that is what they are.
-  */
-extern VSTRING *cleanup_inbuf;         /* read buffer */
-extern VSTRING *cleanup_temp1;         /* scratch buffer, local use only */
-extern VSTRING *cleanup_temp2;         /* scratch buffer, local use only */
-extern VSTREAM *cleanup_src;           /* current input stream */
-extern VSTREAM *cleanup_dst;           /* current output stream */
-extern MAIL_STREAM *cleanup_handle;    /* mail stream handle */
-extern char *cleanup_queue_id;         /* queue file basename */
-extern time_t cleanup_time;            /* posting time */
-extern char *cleanup_fullname;         /* envelope sender full name */
-extern char *cleanup_sender;           /* envelope sender address */
-extern char *cleanup_from;             /* From: address */
-extern char *cleanup_resent_from;      /* Resent-From: address */
-extern char *cleanup_recip;            /* envelope recipient address */
-extern char *cleanup_return_receipt;   /* return-receipt address */
-extern char *cleanup_errors_to;                /* errors-to address */
-extern int cleanup_flags;              /* processing options */
-extern int cleanup_errs;               /* any badness experienced */
-extern int cleanup_err_mask;           /* allowed badness */
-extern VSTRING *cleanup_header_buf;    /* multi-record header */
-extern int cleanup_headers_seen;       /* which headers were seen */
-extern int cleanup_hop_count;          /* count of received: headers */
-extern ARGV *cleanup_recipients;       /* recipients from regular headers */
-extern ARGV *cleanup_resent_recip;     /* recipients from resent headers */
-extern char *cleanup_resent;           /* any resent- header seen */
-extern BH_TABLE *cleanup_dups;         /* recipient dup filter */
+  * one instance of each per message.
+  */
+typedef struct CLEANUP_STATE {
+    VSTRING *temp1;                    /* scratch buffer, local use only */
+    VSTRING *temp2;                    /* scratch buffer, local use only */
+    VSTREAM *src;                      /* current input stream */
+    VSTREAM *dst;                      /* current output stream */
+    MAIL_STREAM *handle;               /* mail stream handle */
+    char   *queue_id;                  /* queue file basename */
+    time_t  time;                      /* posting time */
+    char   *fullname;                  /* envelope sender full name */
+    char   *sender;                    /* envelope sender address */
+    char   *from;                      /* From: address */
+    char   *resent_from;               /* Resent-From: address */
+    char   *recip;                     /* envelope recipient address */
+    char   *return_receipt;            /* return-receipt address */
+    char   *errors_to;                 /* errors-to address */
+    int     flags;                     /* processing options */
+    int     errs;                      /* any badness experienced */
+    int     err_mask;                  /* allowed badness */
+    VSTRING *header_buf;               /* multi-record header */
+    int     headers_seen;              /* which headers were seen */
+    int     hop_count;                 /* count of received: headers */
+    ARGV   *recipients;                        /* recipients from regular headers */
+    ARGV   *resent_recip;              /* recipients from resent headers */
+    char   *resent;                    /* any resent- header seen */
+    BH_TABLE *dups;                    /* recipient dup filter */
+    long    warn_time;                 /* cleanup_envelope.c */
+    void    (*action) (struct CLEANUP_STATE *, int, char *, int);
+    long    mesg_offset;               /* start of message segment */
+    long    data_offset;               /* start of message content */
+} CLEANUP_STATE;
 
  /*
   * Mappings.
@@ -79,41 +82,49 @@ extern char *cleanup_path;
  /*
   * cleanup_state.c
   */
-extern void cleanup_state_alloc(void);
-extern void cleanup_state_free(void);
+extern CLEANUP_STATE *cleanup_state_alloc(void);
+extern void cleanup_state_free(CLEANUP_STATE *);
+
+ /*
+  * cleanup_api.c
+  */
+extern CLEANUP_STATE *cleanup_open(void);
+extern void cleanup_control(CLEANUP_STATE *, int);
+extern int cleanup_close(CLEANUP_STATE *);
+extern void cleanup_all(void);
+
+#define CLEANUP_RECORD(s, t, b, l)     ((s)->action((s), (t), (b), (l)))
 
  /*
   * cleanup_out.c
   */
-extern void cleanup_out(int, char *, int);
-extern void cleanup_out_string(int, char *);
-extern void cleanup_out_format(int, char *,...);
+extern void cleanup_out(CLEANUP_STATE *, int, char *, int);
+extern void cleanup_out_string(CLEANUP_STATE *, int, char *);
+extern void cleanup_out_format(CLEANUP_STATE *, int, char *,...);
 
-#define CLEANUP_OUT_BUF(t, b) \
-       cleanup_out((t), vstring_str((b)), VSTRING_LEN((b)))
+#define CLEANUP_OUT_BUF(s, t, b) \
+       cleanup_out((s), (t), vstring_str((b)), VSTRING_LEN((b)))
 
-#define CLEANUP_OUT_OK() \
-       ((cleanup_errs & cleanup_err_mask) == 0)
+#define CLEANUP_OUT_OK(s)      (((s)->errs & (s)->err_mask) == 0)
 
  /*
   * cleanup_envelope.c
   */
-extern void cleanup_envelope(void);
+extern void cleanup_envelope_init(CLEANUP_STATE *, int, char *, int);
+extern void cleanup_envelope_process(CLEANUP_STATE *, int, char *, int);
 
  /*
   * cleanup_message.c
   */
-extern void cleanup_message(void);
+extern void cleanup_message_init(CLEANUP_STATE *, int, char *, int);
+extern void cleanup_message_header(CLEANUP_STATE *, int, char *, int);
+extern void cleanup_message_body(CLEANUP_STATE *, int, char *, int);
 
  /*
   * cleanup_extracted.c
   */
-extern void cleanup_extracted(void);
-
- /*
-  * cleanup_skip.o
-  */
-extern void cleanup_skip(void);
+extern void cleanup_extracted_init(CLEANUP_STATE *, int, char *, int);
+extern void cleanup_extracted_process(CLEANUP_STATE *, int, char *, int);
 
  /*
   * cleanup_rewrite.c
@@ -125,14 +136,14 @@ extern void cleanup_rewrite_tree(TOK822 *);
  /*
   * cleanup_map11.c
   */
-extern void cleanup_map11_external(VSTRING *, MAPS *, int);
-extern void cleanup_map11_internal(VSTRING *, MAPS *, int);
-extern void cleanup_map11_tree(TOK822 *, MAPS *, int);
+extern void cleanup_map11_external(CLEANUP_STATE *, VSTRING *, MAPS *, int);
+extern void cleanup_map11_internal(CLEANUP_STATE *, VSTRING *, MAPS *, int);
+extern void cleanup_map11_tree(CLEANUP_STATE *, TOK822 *, MAPS *, int);
 
  /*
   * cleanup_map1n.c
   */
-ARGV   *cleanup_map1n_internal(char *, MAPS *, int);
+ARGV   *cleanup_map1n_internal(CLEANUP_STATE *, char *, MAPS *, int);
 
  /*
   * cleanup_masquerade.c
@@ -144,7 +155,7 @@ extern void cleanup_masquerade_tree(TOK822 *, ARGV *);
  /*
   * Cleanup_recipient.c
   */
-extern void cleanup_out_recipient(char *);
+extern void cleanup_out_recipient(CLEANUP_STATE *, char *);
 
 /* LICENSE
 /* .ad
diff --git a/postfix/cleanup/cleanup_api.c b/postfix/cleanup/cleanup_api.c
new file mode 100644 (file)
index 0000000..7d795b0
--- /dev/null
@@ -0,0 +1,285 @@
+/*++
+/* NAME
+/*     cleanup_api 3
+/* SUMMARY
+/*     callable interface
+/* SYNOPSIS
+/*     #include "cleanup.h"
+/*
+/*     char    *cleanup_path;
+/*
+/*     void    cleanup_all()
+/*
+/*     CLEANUP_STATE *cleanup_open()
+/*
+/*     void    cleanup_control(state, flags)
+/*     CLEANUP_STATE *state;
+/*     int     flags;
+/*
+/*     void    CLEANUP_RECORD(state, type, buf, len)
+/*     CLEANUP_STATE *state;
+/*     int     type;
+/*     char    *buf;
+/*     int     len;
+/*
+/*     int     cleanup_close(state)
+/*     CLEANUP_STATE *state;
+/* DESCRIPTION
+/*     This module implements a callable interface to the cleanup service.
+/*     For a description of the cleanup service, see cleanup(8).
+/*
+/*     cleanup_path is a null pointer or it is the name of the queue
+/*     file that currently is being written. This information is used
+/*     by cleanup_all() to clean up in case of fatal errors.
+/*
+/*     cleanup_open() creates a new queue file and performs other
+/*     initialization. The result is a handle that should be given
+/*     to the cleanup_control(), cleanup_record() and cleanup_close()
+/*     routines. The name of the queue file is in the queue_id result
+/*     structure member.
+/*
+/*     cleanup_control() processes flags specified by the caller.
+/*     These flags control what happens in case of data errors.
+/*
+/*     CLEANUP_RECORD() processes one queue file record and maintains
+/*     a little state machine. CLEANUP_RECORD() is a macro that calls
+/*     the appropriate routine depending on what section of a queue file
+/*     is being processed. In order to find out if a file is corrupted,
+/*     the caller can test the CLEANUP_OUT_OK(state) macro. The result is
+/*     false when further message processing is futile.
+/*
+/*     cleanup_close() finishes a queue file. In case of any errors,
+/*     the file is removed. The result status is non-zero in case of
+/*     problems. use cleanup_strerror() to translate the result into
+/*     human_readable text.
+/*
+/*     cleanup_all() should be called in case of fatal error, in order
+/*     to remove an incomplete queue file. Typically one registers a 
+/*     msg_cleanup() handler and a signal() handler that call
+/*     cleanup_all() before terminating the process.
+/* STANDARDS
+/*     RFC 822 (ARPA Internet Text Messages)
+/* DIAGNOSTICS
+/*     Problems and transactions are logged to \fBsyslogd\fR(8).
+/* SEE ALSO
+/*     cleanup(8) cleanup service description.
+/* FILES
+/*     /etc/postfix/canonical*, canonical mapping table
+/*     /etc/postfix/virtual*, virtual mapping table
+/* 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 <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <mymalloc.h>
+
+/* Global library. */
+
+#include <cleanup_user.h>
+#include <mail_queue.h>
+#include <mail_proto.h>
+#include <opened.h>
+#include <bounce.h>
+#include <mail_params.h>
+#include <mail_stream.h>
+#include <mail_addr.h>
+
+/* Application-specific. */
+
+#include "cleanup.h"
+
+ /*
+  * Global state: any queue files that we have open, so that the error
+  * handler can clean up in case of trouble.
+  */
+char   *cleanup_path;                  /* queue file name */
+
+/* cleanup_open - open queue file and initialize */
+
+CLEANUP_STATE * cleanup_open(void)
+{
+    CLEANUP_STATE *state;
+    static char *log_queues[] = {
+       MAIL_QUEUE_DEFER,
+       MAIL_QUEUE_BOUNCE,
+       0,
+    };
+    char  **cpp;
+
+    /*
+     * Initialize.
+     */
+    state = cleanup_state_alloc();
+
+    /*
+     * Open the queue file. Send the queue ID to the client so they can use
+     * it for logging purposes. For example, the SMTP server sends the queue
+     * id to the SMTP client after completion of the DATA command; and when
+     * the local delivery agent forwards a message, it logs the new queue id
+     * together with the old one. All this is done to make it easier for mail
+     * admins to follow a message while it hops from machine to machine.
+     * 
+     * Save the queue file name, so that the runtime error handler can clean up
+     * in case of problems.
+     */
+    state->handle = mail_stream_file(MAIL_QUEUE_INCOMING,
+                                    MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE);
+    state->dst = state->handle->stream;
+    cleanup_path = mystrdup(VSTREAM_PATH(state->dst));
+    state->queue_id = mystrdup(state->handle->id);
+    if (msg_verbose)
+       msg_info("cleanup_open: open %s", cleanup_path);
+
+    /*
+     * If there is a time to get rid of spurious bounce/defer log files, this
+     * is it. The down side is that this costs performance for every message,
+     * while the probability of spurious bounce/defer log files is quite low.
+     * Perhaps we should put the queue file ID inside the defer and bounce
+     * files, so that the bounce and defer daemons can figure out if a file
+     * is a left-over from a previous message instance. For now, we play safe
+     * and check each time a new queue file is created.
+     */
+    for (cpp = log_queues; *cpp; cpp++) {
+       if (mail_queue_remove(*cpp, state->queue_id) == 0)
+           msg_warn("%s: removed spurious %s log", *cpp, state->queue_id);
+       else if (errno != ENOENT)
+           msg_fatal("%s: remove %s log: %m", *cpp, state->queue_id);
+    }
+    return (state);
+}
+
+/* cleanup_control - process client options */
+
+void    cleanup_control(CLEANUP_STATE *state, int flags)
+{
+
+    /*
+     * If the client requests us to do the bouncing in case of problems,
+     * throw away the input only in case of real show-stopper errors, such as
+     * unrecognizable data (which should never happen) or insufficient space
+     * for the queue file (which will happen occasionally). Otherwise,
+     * discard input after any lethal error. See the CLEANUP_OUT_OK()
+     * definition.
+     */
+    if ((state->flags = flags) & CLEANUP_FLAG_BOUNCE) {
+       state->err_mask =
+       (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE | CLEANUP_STAT_SIZE);
+    } else {
+       state->err_mask = CLEANUP_STAT_LETHAL;
+    }
+}
+
+/* cleanup_close - finish queue file */
+
+int     cleanup_close(CLEANUP_STATE *state)
+{
+    char   *junk;
+    int     status;
+
+    /*
+     * Now that we have captured the entire message, see if there are any
+     * other errors. For example, if the message needs to be bounced for lack
+     * of recipients. We want to turn on the execute bits on a file only when
+     * we want the queue manager to process it.
+     */
+    if (state->recip == 0)
+       state->errs |= CLEANUP_STAT_RCPT;
+
+    /*
+     * If there are no errors, be very picky about queue file write errors
+     * because we are about to tell the sender that it can throw away its
+     * copy of the message.
+     */
+    if (state->errs == 0)
+       state->errs |= mail_stream_finish(state->handle);
+    else
+       mail_stream_cleanup(state->handle);
+    state->handle = 0;
+    state->dst = 0;
+
+    /*
+     * If there was an error, remove the queue file, after optionally
+     * bouncing it. An incomplete message should never be bounced: it was
+     * canceled by the client, and may not even have an address to bounce to.
+     * That last test is redundant but we keep it just for robustness.
+     * 
+     * If we are responsible for bouncing a message, we must must report success
+     * to the client unless the bounce message file could not be written
+     * (which is just as bad as not being able to write the message queue
+     * file in the first place).
+     * 
+     * Do not log the arrival of a message that will be bounced by the client.
+     * 
+     * XXX CLEANUP_STAT_LETHAL masks errors that are not directly fatal (e.g.,
+     * header buffer overflow is normally allowed to happen), but that can
+     * indirectly become a problem (e.g., no recipients were extracted from
+     * message headers because we could not process all the message headers).
+     * However, cleanup_strerror() prioritizes errors so that it can report
+     * the cause (e.g., header buffer overflow), which is more useful.
+     * Amazing.
+     */
+#define CAN_BOUNCE() \
+       ((state->errs & (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE)) == 0 \
+           && state->sender != 0 \
+           && (state->flags & CLEANUP_FLAG_BOUNCE) != 0)
+
+    if (state->errs & CLEANUP_STAT_LETHAL) {
+       if (CAN_BOUNCE()) {
+           if (bounce_recip(BOUNCE_FLAG_CLEAN,
+                            MAIL_QUEUE_INCOMING, state->queue_id,
+                            state->sender, state->recip ?
+                            state->recip : "", "cleanup", state->time,
+                            "Message rejected: %s",
+                            cleanup_strerror(state->errs)) == 0) {
+               state->errs = 0;
+           } else {
+               msg_warn("%s: bounce message failure", state->queue_id);
+               state->errs = CLEANUP_STAT_WRITE;
+           }
+       }
+       if (REMOVE(cleanup_path))
+           msg_warn("remove %s: %m", cleanup_path);
+    }
+
+    /*
+     * Make sure that our queue file will not be deleted by the error handler
+     * AFTER we have taken responsibility for delivery. Better to deliver
+     * twice than to lose mail.
+     */
+    junk = cleanup_path;
+    cleanup_path = 0;                          /* don't delete upon error */
+    myfree(junk);
+
+    /*
+     * Cleanup internal state. This is simply complementary to the
+     * initializations at the beginning of cleanup_open().
+     */
+    if (msg_verbose)
+       msg_info("cleanup_close: status %d", state->errs);
+    status = state->errs & CLEANUP_STAT_LETHAL;
+    cleanup_state_free(state);
+    return (status);
+}
+
+/* cleanup_all - callback for the runtime error handler */
+
+void cleanup_all(void)
+{
+    if (cleanup_path && REMOVE(cleanup_path))
+       msg_warn("cleanup_all: remove %s: %m", cleanup_path);
+}
index dab3525e04317bb69e876bc9e903caf9fbfff06f..1ca238e2be011a44bb752a45b9af98508d23482c 100644 (file)
@@ -6,13 +6,23 @@
 /* SYNOPSIS
 /*     #include <cleanup.h>
 /*
-/*     void    cleanup_envelope()
+/*     void    cleanup_envelope_init(state, type, buf, len)
+/*     CLEANUP_STATE *state;
+/*     int     type;
+/*     char    *buf;
+/*     int     len;
+/*
+/*     void    cleanup_envelope_process(state, type, buf, len)
+/*     CLEANUP_STATE *state;
+/*     int     type;
+/*     char    *buf;
+/*     int     len;
 /* DESCRIPTION
 /*     This module processes the envelope segment of a mail message.
 /*     While copying records from input to output it validates the
 /*     message structure, rewrites sender/recipient addresses
-/*     to canonical form, and expands recipients according to
-/*     entries in the virtual table.
+/*     to canonical form, expands recipients according to
+/*     entries in the virtual table, and updates the state structure.
 /* LICENSE
 /* .ad
 /* .fi
 
 #define STR    vstring_str
 
-/* cleanup_envelope - process envelope segment */
+/* cleanup_envelope_init - initialization */
 
-void    cleanup_envelope(void)
+void    cleanup_envelope_init(CLEANUP_STATE *state, int type, char *str, int len)
 {
-    VSTRING *clean_addr = vstring_alloc(100);
-    int     type = 0;
-    long    warn_time = 0;
 
     /*
      * The message content size record goes first, so it can easily be
@@ -66,92 +73,87 @@ void    cleanup_envelope(void)
      * estimate provided by the client. Size goes first so that it it easy to
      * produce queue file reports.
      */
-    cleanup_out_format(REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT, 0L);
+    cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT, 0L);
+    state->action = cleanup_envelope_process;
+    cleanup_envelope_process(state, type, str, len);
+}
 
-    /*
-     * XXX Rely on the front-end programs to enforce record size limits.
-     */
-    while (CLEANUP_OUT_OK()) {
-       if ((type = rec_get(cleanup_src, cleanup_inbuf, 0)) < 0) {
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           break;
-       }
-       if (type == REC_TYPE_MESG) {
-           if (cleanup_sender == 0 || cleanup_time == 0) {
-               msg_warn("%s: missing sender or time envelope record",
-                        cleanup_queue_id);
-               cleanup_errs |= CLEANUP_STAT_BAD;
-           } else {
-               if (warn_time == 0 && var_delay_warn_time > 0)
-                   warn_time = cleanup_time + var_delay_warn_time * 3600L;
-               if (warn_time)
-                   cleanup_out_format(REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
-                                      warn_time);
-           }
-           break;
-       }
-       if (strchr(REC_TYPE_ENVELOPE, type) == 0) {
-           msg_warn("%s: unexpected record type %d in envelope",
-                    cleanup_queue_id, type);
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           break;
+/* cleanup_envelope_process - process one envelope record */
+
+void    cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf, int len)
+{
+    if (type == REC_TYPE_MESG) {
+       if (state->sender == 0 || state->time == 0) {
+           msg_warn("%s: missing sender or time envelope record",
+                    state->queue_id);
+           state->errs |= CLEANUP_STAT_BAD;
+       } else {
+           if (state->warn_time == 0 && var_delay_warn_time > 0)
+               state->warn_time = state->time + var_delay_warn_time * 3600L;
+           if (state->warn_time)
+               cleanup_out_format(state, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
+                                  state->warn_time);
+           state->action = cleanup_message_init;
        }
-       if (msg_verbose)
-           msg_info("envelope %c %s", type, STR(cleanup_inbuf));
-
-       if (type == REC_TYPE_TIME) {
-           cleanup_time = atol(STR(cleanup_inbuf));
-           CLEANUP_OUT_BUF(type, cleanup_inbuf);
-       } else if (type == REC_TYPE_FULL) {
-           cleanup_fullname = mystrdup(STR(cleanup_inbuf));
-       } else if (type == REC_TYPE_FROM) {
-           cleanup_rewrite_internal(clean_addr, STR(cleanup_inbuf));
-           if (cleanup_send_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_send_canon_maps,
+       return;
+    }
+    if (strchr(REC_TYPE_ENVELOPE, type) == 0) {
+       msg_warn("%s: unexpected record type %d in envelope",
+                state->queue_id, type);
+       state->errs |= CLEANUP_STAT_BAD;
+       return;
+    }
+    if (msg_verbose)
+       msg_info("envelope %c %.*s", type, len, buf);
+
+    if (type == REC_TYPE_TIME) {
+       state->time = atol(buf);
+       cleanup_out(state, type, buf, len);
+    } else if (type == REC_TYPE_FULL) {
+       state->fullname = mystrdup(buf);
+    } else if (type == REC_TYPE_FROM) {
+       VSTRING *clean_addr = vstring_alloc(100);
+
+       cleanup_rewrite_internal(clean_addr, buf);
+       if (cleanup_send_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_send_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+       if (cleanup_comm_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           if (cleanup_masq_domains)
-               cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
-           CLEANUP_OUT_BUF(type, clean_addr);
-           if (cleanup_sender == 0)
-               cleanup_sender = mystrdup(STR(clean_addr));
-       } else if (type == REC_TYPE_RCPT) {
-           if (cleanup_sender == 0) {          /* protect showq */
-               msg_warn("%s: envelope recipient precedes sender",
-                        cleanup_queue_id);
-               cleanup_errs |= CLEANUP_STAT_BAD;
-               break;
-           }
-           cleanup_rewrite_internal(clean_addr, *STR(cleanup_inbuf) ?
-                                    STR(cleanup_inbuf) : var_empty_addr);
-           if (cleanup_rcpt_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps,
+       if (cleanup_masq_domains)
+           cleanup_masquerade_internal(clean_addr, cleanup_masq_domains);
+       CLEANUP_OUT_BUF(state, type, clean_addr);
+       if (state->sender == 0)
+           state->sender = mystrdup(STR(clean_addr));
+       vstring_free(clean_addr);
+    } else if (type == REC_TYPE_RCPT) {
+       VSTRING *clean_addr = vstring_alloc(100);
+
+       if (state->sender == 0) {               /* protect showq */
+           msg_warn("%s: envelope recipient precedes sender",
+                    state->queue_id);
+           state->errs |= CLEANUP_STAT_BAD;
+           return;
+       }
+       cleanup_rewrite_internal(clean_addr, *buf ?
+                                buf : var_empty_addr);
+       if (cleanup_rcpt_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+       if (cleanup_comm_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           cleanup_out_recipient(STR(clean_addr));
-           if (cleanup_recip == 0)
-               cleanup_recip = mystrdup(STR(clean_addr));
-       } else if (type == REC_TYPE_WARN) {
-           if ((warn_time = atol(STR(cleanup_inbuf))) < 0) {
-               cleanup_errs |= CLEANUP_STAT_BAD;
-               break;
-           }
-       } else {
-           CLEANUP_OUT_BUF(type, cleanup_inbuf);
+       cleanup_out_recipient(state, STR(clean_addr));
+       if (state->recip == 0)
+           state->recip = mystrdup(STR(clean_addr));
+       vstring_free(clean_addr);
+    } else if (type == REC_TYPE_WARN) {
+       if ((state->warn_time = atol(buf)) < 0) {
+           state->errs |= CLEANUP_STAT_BAD;
+           return;
        }
+    } else {
+       cleanup_out(state, type, buf, len);
     }
-
-    /*
-     * XXX Keep reading in case of trouble, so that the sender is ready to
-     * receive our status report.
-     */
-    if (!CLEANUP_OUT_OK())
-       if (type >= 0)
-           cleanup_skip();
-
-    vstring_free(clean_addr);
 }
index f7e2b94b943204129710f7a0562ad19ec8d1c499..dd5a7151df25739a28411249ab4338a15772ac78 100644 (file)
 
 #define STR(x) vstring_str(x)
 
-/* cleanup_extracted - generate segment with header-extracted information */
+/* cleanup_extracted_init - initialize extracted segment */
 
-void    cleanup_extracted(void)
+void    cleanup_extracted_init(CLEANUP_STATE *state, int type, char *buf, int len)
+{
+
+    /*
+     * Start the extracted segment.
+     */
+    cleanup_out_string(state, REC_TYPE_XTRA, "");
+    state->action = cleanup_extracted_process;
+    cleanup_extracted_process(state, type, buf, len);
+}
+
+/* cleanup_extracted_process - process extracted segment */
+
+void    cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf, int unused_len)
 {
     VSTRING *clean_addr;
     ARGV   *rcpt;
     char  **cpp;
-    int     type;
 
-    /*
-     * Do not complain in case of premature EOF - most likely the client
-     * aborted the operation.
-     * 
-     * XXX Rely on the front-end programs to enforce record size limits.
-     */
-    while (CLEANUP_OUT_OK()) {
-       if ((type = rec_get(cleanup_src, cleanup_inbuf, 0)) < 0) {
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           return;
-       }
-       if (type == REC_TYPE_RRTO) {
-            /* XXX Use extracted information instead. */ ;
-       } else if (type == REC_TYPE_ERTO) {
-            /* XXX Use extracted information instead. */ ;
-       } else if (type == REC_TYPE_RCPT) {
-           clean_addr = vstring_alloc(100);
-           cleanup_rewrite_internal(clean_addr, *STR(cleanup_inbuf) ?
-                                    STR(cleanup_inbuf) : var_empty_addr);
-           if (cleanup_rcpt_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps,
+    if (type == REC_TYPE_RRTO) {
+       /* XXX Use extracted information instead. */
+       return;
+    }
+    if (type == REC_TYPE_ERTO) {
+       /* XXX Use extracted information instead. */
+       return;
+    }
+    if (type == REC_TYPE_RCPT) {
+       clean_addr = vstring_alloc(100);
+       cleanup_rewrite_internal(clean_addr, *buf ? buf : var_empty_addr);
+       if (cleanup_rcpt_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+       if (cleanup_comm_canon_maps)
+           cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-           cleanup_out_recipient(STR(clean_addr));
-           if (cleanup_recip == 0)
-               cleanup_recip = mystrdup(STR(clean_addr));
-           vstring_free(clean_addr);
-       } else if (type == REC_TYPE_END) {
-           break;
-       } else {
-           msg_warn("%s: unexpected record type %d in extracted segment",
-                    cleanup_queue_id, type);
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           if (type >= 0)
-               cleanup_skip();
-           return;
-       }
+       cleanup_out_recipient(state, STR(clean_addr));
+       if (state->recip == 0)
+           state->recip = mystrdup(STR(clean_addr));
+       vstring_free(clean_addr);
+       return;
+    }
+    if (type != REC_TYPE_END) {
+       msg_warn("%s: unexpected record type %d in extracted segment",
+                state->queue_id, type);
+       state->errs |= CLEANUP_STAT_BAD;
+       return;
     }
 
     /*
-     * Start the extracted segment.
-     */
-    cleanup_out_string(REC_TYPE_XTRA, "");
-
-    /*
-     * Always emit Return-Receipt-To and Errors-To records, and always emit
-     * them ahead of extracted recipients, so that the queue manager does not
-     * waste lots of time searching through large numbers of recipient
-     * addresses.
+     * Always emit Return-Receipt-To and Errors-To records, and always try to
+     * emit them ahead of extracted recipients, so that the queue manager
+     * does not waste lots of time searching through large numbers of
+     * recipient addresses.
      */
-    cleanup_out_string(REC_TYPE_RRTO, cleanup_return_receipt ?
-                      cleanup_return_receipt : "");
+    cleanup_out_string(state, REC_TYPE_RRTO, state->return_receipt ?
+                      state->return_receipt : "");
 
-    cleanup_out_string(REC_TYPE_ERTO, cleanup_errors_to ?
-                      cleanup_errors_to : cleanup_sender);
+    cleanup_out_string(state, REC_TYPE_ERTO, state->errors_to ?
+                      state->errors_to : state->sender);
 
     /*
      * Optionally account for missing recipient envelope records.
      * 
+     * Don't extract recipients when some header was too long. We have
+     * incomplete information.
+     * 
      * XXX Code duplication from cleanup_envelope.c. This should be in one
      * place.
      */
-    if (cleanup_recip == 0) {
-       rcpt = (cleanup_resent[0] ? cleanup_resent_recip : cleanup_recipients);
+    if (state->recip == 0 && (state->errs & CLEANUP_STAT_HOVFL) == 0) {
+       rcpt = (state->resent[0] ? state->resent_recip : state->recipients);
        if (*var_always_bcc && rcpt->argv[0]) {
            clean_addr = vstring_alloc(100);
            cleanup_rewrite_internal(clean_addr, var_always_bcc);
            if (cleanup_rcpt_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps,
+               cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            if (cleanup_comm_canon_maps)
-               cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+               cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps,
                                cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
            argv_add(rcpt, STR(clean_addr), (char *) 0);
            vstring_free(clean_addr);
        }
        argv_terminate(rcpt);
-       for (cpp = rcpt->argv; CLEANUP_OUT_OK() && *cpp; cpp++)
-           cleanup_out_recipient(*cpp);
+       for (cpp = rcpt->argv; CLEANUP_OUT_OK(state) && *cpp; cpp++)
+           cleanup_out_recipient(state, *cpp);
        if (rcpt->argv[0])
-           cleanup_recip = mystrdup(rcpt->argv[0]);
+           state->recip = mystrdup(rcpt->argv[0]);
     }
 
     /*
      * Terminate the extracted segment.
      */
-    cleanup_out_string(REC_TYPE_END, "");
+    cleanup_out_string(state, REC_TYPE_END, "");
 }
index 96069324a90217dc2e66b0fe438f311ee7173bae..6d699d3483b1da4371df653d2f28fa8f91846dcb 100644 (file)
@@ -6,17 +6,20 @@
 /* SYNOPSIS
 /*     #include <cleanup.h>
 /*
-/*     void    cleanup_map11_external(addr, maps, propagate)
+/*     void    cleanup_map11_external(state, addr, maps, propagate)
+/*     CLEANUP_STATE *state;
 /*     VSTRING *addr;
 /*     MAPS    *maps;
 /*     int     propagate;
 /*
-/*     void    cleanup_map11_internal(addr, maps, propagate)
+/*     void    cleanup_map11_internal(state, addr, maps, propagate)
+/*     CLEANUP_STATE *state;
 /*     VSTRING *addr;
 /*     MAPS    *maps;
 /*     int     propagate;
 /*
-/*     void    cleanup_map11_tree(tree, maps, propagate)
+/*     void    cleanup_map11_tree(state, tree, maps, propagate)
+/*     CLEANUP_STATE *state;
 /*     TOK822  *tree;
 /*     MAPS    *maps;
 /*     int     propagate;
@@ -27,7 +30,7 @@
 /*     subjected to another iteration of rewriting and mapping.
 /*     Recursion continues until an address maps onto itself,
 /*     or until an unreasonable recursion level is reached.
-/*     An unmatched address extension is propagated when 
+/*     An unmatched address extension is propagated when
 /*     \fIpropagate\fR is non-zero.
 /*
 /*     cleanup_map11_external() looks up the external (quoted) string
@@ -87,7 +90,8 @@
 
 /* cleanup_map11_external - one-to-one table lookups */
 
-void    cleanup_map11_external(VSTRING *addr, MAPS *maps, int propagate)
+void    cleanup_map11_external(CLEANUP_STATE *state, VSTRING *addr,
+                                      MAPS *maps, int propagate)
 {
     int     count;
     int     expand_to_self;
@@ -104,7 +108,7 @@ void    cleanup_map11_external(VSTRING *addr, MAPS *maps, int propagate)
        if ((new_addr = mail_addr_map(maps, STR(addr), propagate)) != 0) {
            if (new_addr->argc > 1)
                msg_warn("%s: multi-valued %s entry for %s",
-                        cleanup_queue_id, maps->title, STR(addr));
+                        state->queue_id, maps->title, STR(addr));
            saved_addr = mystrdup(STR(addr));
            vstring_strcpy(addr, new_addr->argv[0]);
            expand_to_self = !strcasecmp(saved_addr, STR(addr));
@@ -114,20 +118,21 @@ void    cleanup_map11_external(VSTRING *addr, MAPS *maps, int propagate)
                return;
        } else if (dict_errno != 0) {
            msg_warn("%s: %s map lookup problem for %s",
-                    cleanup_queue_id, maps->title, STR(addr));
-           cleanup_errs |= CLEANUP_STAT_WRITE;
+                    state->queue_id, maps->title, STR(addr));
+           state->errs |= CLEANUP_STAT_WRITE;
            return;
        } else {
            return;
        }
     }
     msg_warn("%s: unreasonable %s map nesting for %s",
-            cleanup_queue_id, maps->title, STR(addr));
+            state->queue_id, maps->title, STR(addr));
 }
 
 /* cleanup_map11_tree - rewrite address node */
 
-void    cleanup_map11_tree(TOK822 *tree, MAPS *maps, int propagate)
+void    cleanup_map11_tree(CLEANUP_STATE *state, TOK822 *tree,
+                                  MAPS *maps, int propagate)
 {
     VSTRING *temp = vstring_alloc(100);
 
@@ -138,7 +143,7 @@ void    cleanup_map11_tree(TOK822 *tree, MAPS *maps, int propagate)
      * the place.
      */
     tok822_externalize(temp, tree->head, TOK822_STR_DEFL);
-    cleanup_map11_external(temp, maps, propagate);
+    cleanup_map11_external(state, temp, maps, propagate);
     tok822_free_tree(tree->head);
     tree->head = tok822_scan(STR(temp), &tree->tail);
     vstring_free(temp);
@@ -146,7 +151,8 @@ void    cleanup_map11_tree(TOK822 *tree, MAPS *maps, int propagate)
 
 /* cleanup_map11_internal - rewrite address internal form */
 
-void    cleanup_map11_internal(VSTRING *addr, MAPS *maps, int propagate)
+void    cleanup_map11_internal(CLEANUP_STATE *state, VSTRING *addr,
+                                      MAPS *maps, int propagate)
 {
     VSTRING *temp = vstring_alloc(100);
 
@@ -157,7 +163,7 @@ void    cleanup_map11_internal(VSTRING *addr, MAPS *maps, int propagate)
      * the place.
      */
     quote_822_local(temp, STR(addr));
-    cleanup_map11_external(temp, maps, propagate);
+    cleanup_map11_external(state, temp, maps, propagate);
     unquote_822_local(addr, STR(temp));
     vstring_free(temp);
 }
index 2bab163df5b3ed95d06583fb9528beacd3f2cb69..bd7303ddfa9bff7707d9f21ef8fe9c7f7fc1c97d 100644 (file)
@@ -61,7 +61,8 @@
 
 /* cleanup_map1n_internal - one-to-many table lookups */
 
-ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps, int propagate)
+ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, char *addr,
+                                      MAPS *maps, int propagate)
 {
     ARGV   *argv;
     ARGV   *lookup;
@@ -93,25 +94,25 @@ ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps, int propagate)
     for (expand_to_self = 0, arg = 0; arg < argv->argc; arg++) {
        if (argv->argc > MAX_EXPANSION) {
            msg_warn("%s: unreasonable %s map expansion size for %s",
-                    cleanup_queue_id, maps->title, addr);
+                    state->queue_id, maps->title, addr);
            break;
        }
        for (count = 0; /* void */ ; count++) {
            if (count >= MAX_RECURSION) {
                msg_warn("%s: unreasonable %s map nesting for %s",
-                        cleanup_queue_id, maps->title, addr);
+                        state->queue_id, maps->title, addr);
                break;
            }
            if ((lookup = mail_addr_map(maps, argv->argv[arg], propagate)) != 0) {
                saved_lhs = mystrdup(argv->argv[arg]);
                for (i = 0; i < lookup->argc; i++) {
-                   unquote_822_local(cleanup_temp1, lookup->argv[i]);
-                   if (strcasecmp(saved_lhs, STR(cleanup_temp1)) == 0)
+                   unquote_822_local(state->temp1, lookup->argv[i]);
+                   if (strcasecmp(saved_lhs, STR(state->temp1)) == 0)
                        expand_to_self = 1;
                    if (i == 0) {
-                       UPDATE(argv->argv[arg], STR(cleanup_temp1));
+                       UPDATE(argv->argv[arg], STR(state->temp1));
                    } else {
-                       argv_add(argv, STR(cleanup_temp1), ARGV_END);
+                       argv_add(argv, STR(state->temp1), ARGV_END);
                        argv_terminate(argv);
                    }
                }
@@ -121,8 +122,8 @@ ARGV   *cleanup_map1n_internal(char *addr, MAPS *maps, int propagate)
                    return (argv);
            } else if (dict_errno != 0) {
                msg_warn("%s: %s map lookup problem for %s",
-                        cleanup_queue_id, maps->title, addr);
-               cleanup_errs |= CLEANUP_STAT_WRITE;
+                        state->queue_id, maps->title, addr);
+               state->errs |= CLEANUP_STAT_WRITE;
                return (argv);
            } else {
                break;
index 25c55bcf972cd46385c3c63369835f1ebf864be6..e35a3b4da18cc9398447e8f257687b77d7095d11 100644 (file)
@@ -6,7 +6,16 @@
 /* SYNOPSIS
 /*     #include "cleanup.h"
 /*
-/*     void    cleanup_message(void)
+/*     void    cleanup_message_init(state, type, buf, len)
+/*     CLEANUP_STATE *state;
+/*     int     type;
+/*     char    *buf;
+/*
+/*     void    cleanup_message_process(state, type, buf, len)
+/*     CLEANUP_STATE *state;
+/*     int     type;
+/*     char    *buf;
+/*     int     len;
 /* DESCRIPTION
 /*     This module processes message content segments.
 /*     While copying records from input to output, it validates
 
 /* cleanup_out_header - output one header as a bunch of records */
 
-static void cleanup_out_header(void)
+static void cleanup_out_header(CLEANUP_STATE *state)
 {
-    char   *start = vstring_str(cleanup_header_buf);
+    char   *start = vstring_str(state->header_buf);
     char   *line;
     char   *next_line;
 
     /*
      * Prepend a tab to continued header lines that went through the address
-     * rewriting machinery. See cleanup_fold_header() below for the form of
-     * such header lines. NB: This code destroys the header. We could try to
-     * avoid clobbering it, but we're not going to use the data any further.
+     * rewriting machinery. See cleanup_fold_header(state) below for the form
+     * of such header lines. NB: This code destroys the header. We could try
+     * to avoid clobbering it, but we're not going to use the data any
+     * further.
      */
     for (line = start; line; line = next_line) {
        next_line = split_at(line, '\n');
        if (line == start || ISSPACE(*line)) {
-           cleanup_out_string(REC_TYPE_NORM, line);
+           cleanup_out_string(state, REC_TYPE_NORM, line);
        } else {
-           cleanup_out_format(REC_TYPE_NORM, "\t%s", line);
+           cleanup_out_format(state, REC_TYPE_NORM, "\t%s", line);
        }
     }
 }
 
 /* cleanup_fold_header - wrap address list header */
 
-static void cleanup_fold_header(void)
+static void cleanup_fold_header(CLEANUP_STATE *state)
 {
-    char   *start_line = vstring_str(cleanup_header_buf);
+    char   *start_line = vstring_str(state->header_buf);
     char   *end_line;
     char   *next_line;
     char   *line;
@@ -116,7 +126,7 @@ static void cleanup_fold_header(void)
        }
        next_line = *end_line ? end_line + 1 : 0;
     }
-    cleanup_out_header();
+    cleanup_out_header(state);
 }
 
 /* cleanup_extract_internal - save unquoted copy of extracted address */
@@ -134,7 +144,7 @@ static char *cleanup_extract_internal(VSTRING *buffer, TOK822 *addr)
 
 /* cleanup_rewrite_sender - sender address rewriting */
 
-static void cleanup_rewrite_sender(HEADER_OPTS *hdr_opts)
+static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
 {
     TOK822 *tree;
     TOK822 **addr_list;
@@ -148,36 +158,36 @@ static void cleanup_rewrite_sender(HEADER_OPTS *hdr_opts)
      * sender addresses, and regenerate the header line. Finally, pipe the
      * result through the header line folding routine.
      */
-    tree = tok822_parse(vstring_str(cleanup_header_buf)
+    tree = tok822_parse(vstring_str(state->header_buf)
                        + strlen(hdr_opts->name) + 1);
     addr_list = tok822_grep(tree, TOK822_ADDR);
     for (tpp = addr_list; *tpp; tpp++) {
        cleanup_rewrite_tree(*tpp);
        if (cleanup_send_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_send_canon_maps,
+           cleanup_map11_tree(state, *tpp, cleanup_send_canon_maps,
                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_comm_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps,
+           cleanup_map11_tree(state, *tpp, cleanup_comm_canon_maps,
                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_masq_domains)
            cleanup_masquerade_tree(*tpp, cleanup_masq_domains);
-       if (hdr_opts->type == HDR_FROM && cleanup_from == 0)
-           cleanup_from = cleanup_extract_internal(cleanup_header_buf, *tpp);
-       if (hdr_opts->type == HDR_RESENT_FROM && cleanup_resent_from == 0)
-           cleanup_resent_from =
-               cleanup_extract_internal(cleanup_header_buf, *tpp);
+       if (hdr_opts->type == HDR_FROM && state->from == 0)
+           state->from = cleanup_extract_internal(state->header_buf, *tpp);
+       if (hdr_opts->type == HDR_RESENT_FROM && state->resent_from == 0)
+           state->resent_from =
+               cleanup_extract_internal(state->header_buf, *tpp);
     }
-    vstring_sprintf(cleanup_header_buf, "%s: ", hdr_opts->name);
-    tok822_externalize(cleanup_header_buf, tree, TOK822_STR_HEAD);
+    vstring_sprintf(state->header_buf, "%s: ", hdr_opts->name);
+    tok822_externalize(state->header_buf, tree, TOK822_STR_HEAD);
     myfree((char *) addr_list);
     tok822_free_tree(tree);
     if ((hdr_opts->flags & HDR_OPT_DROP) == 0)
-       cleanup_fold_header();
+       cleanup_fold_header(state);
 }
 
 /* cleanup_rewrite_recip - recipient address rewriting */
 
-static void cleanup_rewrite_recip(HEADER_OPTS *hdr_opts)
+static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts)
 {
     TOK822 *tree;
     TOK822 **addr_list;
@@ -191,57 +201,57 @@ static void cleanup_rewrite_recip(HEADER_OPTS *hdr_opts)
      * recipient addresses, and regenerate the header line. Finally, pipe the
      * result through the header line folding routine.
      */
-    tree = tok822_parse(vstring_str(cleanup_header_buf)
+    tree = tok822_parse(vstring_str(state->header_buf)
                        + strlen(hdr_opts->name) + 1);
     addr_list = tok822_grep(tree, TOK822_ADDR);
     for (tpp = addr_list; *tpp; tpp++) {
        cleanup_rewrite_tree(*tpp);
        if (cleanup_rcpt_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_rcpt_canon_maps,
+           cleanup_map11_tree(state, *tpp, cleanup_rcpt_canon_maps,
                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
        if (cleanup_comm_canon_maps)
-           cleanup_map11_tree(*tpp, cleanup_comm_canon_maps,
+           cleanup_map11_tree(state, *tpp, cleanup_comm_canon_maps,
                               cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
-       tok822_internalize(cleanup_temp1, tpp[0]->head, TOK822_STR_DEFL);
-       if (cleanup_recip == 0 && (hdr_opts->flags & HDR_OPT_EXTRACT) != 0)
+       tok822_internalize(state->temp1, tpp[0]->head, TOK822_STR_DEFL);
+       if (state->recip == 0 && (hdr_opts->flags & HDR_OPT_EXTRACT) != 0)
            argv_add((hdr_opts->flags & HDR_OPT_RR) ?
-                    cleanup_resent_recip : cleanup_recipients,
-                    vstring_str(cleanup_temp1), (char *) 0);
+                    state->resent_recip : state->recipients,
+                    vstring_str(state->temp1), (char *) 0);
        if (cleanup_masq_domains)
            cleanup_masquerade_tree(*tpp, cleanup_masq_domains);
-       if (hdr_opts->type == HDR_RETURN_RECEIPT_TO && !cleanup_return_receipt)
-           cleanup_return_receipt =
-               cleanup_extract_internal(cleanup_header_buf, *tpp);
-       if (hdr_opts->type == HDR_ERRORS_TO && !cleanup_errors_to)
-           cleanup_errors_to =
-               cleanup_extract_internal(cleanup_header_buf, *tpp);
+       if (hdr_opts->type == HDR_RETURN_RECEIPT_TO && !state->return_receipt)
+           state->return_receipt =
+               cleanup_extract_internal(state->header_buf, *tpp);
+       if (hdr_opts->type == HDR_ERRORS_TO && !state->errors_to)
+           state->errors_to =
+               cleanup_extract_internal(state->header_buf, *tpp);
     }
-    vstring_sprintf(cleanup_header_buf, "%s: ", hdr_opts->name);
-    tok822_externalize(cleanup_header_buf, tree, TOK822_STR_HEAD);
+    vstring_sprintf(state->header_buf, "%s: ", hdr_opts->name);
+    tok822_externalize(state->header_buf, tree, TOK822_STR_HEAD);
     myfree((char *) addr_list);
     tok822_free_tree(tree);
     if ((hdr_opts->flags & HDR_OPT_DROP) == 0)
-       cleanup_fold_header();
+       cleanup_fold_header(state);
 }
 
 /* cleanup_header - process one complete header line */
 
-static void cleanup_header(void)
+static void cleanup_header(CLEANUP_STATE *state)
 {
     char   *myname = "cleanup_header";
     HEADER_OPTS *hdr_opts;
 
     if (msg_verbose)
-       msg_info("%s: '%s'", myname, vstring_str(cleanup_header_buf));
+       msg_info("%s: '%s'", myname, vstring_str(state->header_buf));
 
-    if ((cleanup_flags & CLEANUP_FLAG_FILTER) && cleanup_header_checks) {
-       char   *header = vstring_str(cleanup_header_buf);
+    if ((state->flags & CLEANUP_FLAG_FILTER) && cleanup_header_checks) {
+       char   *header = vstring_str(state->header_buf);
        const char *value;
 
        if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) {
            if (strcasecmp(value, "REJECT") == 0) {
-               msg_warn("%s: reject: header %.100s", cleanup_queue_id, header);
-               cleanup_errs |= CLEANUP_STAT_CONT;
+               msg_warn("%s: reject: header %.100s", state->queue_id, header);
+               state->errs |= CLEANUP_STAT_CONT;
            }
        }
     }
@@ -251,8 +261,8 @@ static void cleanup_header(void)
      * even bothering to fold long lines. XXX Should split header lines that
      * do not fit a REC_TYPE_NORM record.
      */
-    if ((hdr_opts = header_opts_find(vstring_str(cleanup_header_buf))) == 0) {
-       cleanup_out_header();
+    if ((hdr_opts = header_opts_find(vstring_str(state->header_buf))) == 0) {
+       cleanup_out_header(state);
     }
 
     /*
@@ -262,25 +272,25 @@ static void cleanup_header(void)
      * because the addresses in those headers might be needed elsewhere.
      */
     else {
-       cleanup_headers_seen |= (1 << hdr_opts->type);
+       state->headers_seen |= (1 << hdr_opts->type);
        if (hdr_opts->type == HDR_MESSAGE_ID)
-           msg_info("%s: message-id=%s", cleanup_queue_id,
-             vstring_str(cleanup_header_buf) + strlen(hdr_opts->name) + 2);
+           msg_info("%s: message-id=%s", state->queue_id,
+              vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2);
        if (hdr_opts->type == HDR_RESENT_MESSAGE_ID)
-           msg_info("%s: resent-message-id=%s", cleanup_queue_id,
-             vstring_str(cleanup_header_buf) + strlen(hdr_opts->name) + 2);
+           msg_info("%s: resent-message-id=%s", state->queue_id,
+              vstring_str(state->header_buf) + strlen(hdr_opts->name) + 2);
        if (hdr_opts->type == HDR_RECEIVED)
-           if (++cleanup_hop_count >= var_hopcount_limit)
-               cleanup_errs |= CLEANUP_STAT_HOPS;
-       if (CLEANUP_OUT_OK()) {
+           if (++state->hop_count >= var_hopcount_limit)
+               state->errs |= CLEANUP_STAT_HOPS;
+       if (CLEANUP_OUT_OK(state)) {
            if (hdr_opts->flags & HDR_OPT_RR)
-               cleanup_resent = "Resent-";
+               state->resent = "Resent-";
            if (hdr_opts->flags & HDR_OPT_SENDER) {
-               cleanup_rewrite_sender(hdr_opts);
+               cleanup_rewrite_sender(state, hdr_opts);
            } else if (hdr_opts->flags & HDR_OPT_RECIP) {
-               cleanup_rewrite_recip(hdr_opts);
+               cleanup_rewrite_recip(state, hdr_opts);
            } else if ((hdr_opts->flags & HDR_OPT_DROP) == 0) {
-               cleanup_out_header();
+               cleanup_out_header(state);
            }
        }
     }
@@ -288,7 +298,7 @@ static void cleanup_header(void)
 
 /* cleanup_missing_headers - insert missing message headers */
 
-static void cleanup_missing_headers(void)
+static void cleanup_missing_headers(CLEANUP_STATE *state)
 {
     char    time_stamp[1024];          /* XXX locale dependent? */
     struct tm *tp;
@@ -299,25 +309,25 @@ static void cleanup_missing_headers(void)
      * Add a missing (Resent-)Message-Id: header. The message ID gives the
      * time in GMT units, plus the local queue ID.
      */
-    if ((cleanup_headers_seen & (1 << (cleanup_resent[0] ?
+    if ((state->headers_seen & (1 << (state->resent[0] ?
                           HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) {
-       tp = gmtime(&cleanup_time);
+       tp = gmtime(&state->time);
        strftime(time_stamp, sizeof(time_stamp), "%Y%m%d%H%M%S", tp);
-       cleanup_out_format(REC_TYPE_NORM, "%sMessage-Id: <%s.%s@%s>",
-             cleanup_resent, time_stamp, cleanup_queue_id, var_myhostname);
+       cleanup_out_format(state, REC_TYPE_NORM, "%sMessage-Id: <%s.%s@%s>",
+               state->resent, time_stamp, state->queue_id, var_myhostname);
        msg_info("%s: %smessage-id=<%s.%s@%s>",
-                cleanup_queue_id, *cleanup_resent ? "resent-" : "",
-                time_stamp, cleanup_queue_id, var_myhostname);
+                state->queue_id, *state->resent ? "resent-" : "",
+                time_stamp, state->queue_id, var_myhostname);
     }
 
     /*
      * Add a missing (Resent-)Date: header. The date is in local time units,
      * with the GMT offset at the end.
      */
-    if ((cleanup_headers_seen & (1 << (cleanup_resent[0] ?
-                                      HDR_RESENT_DATE : HDR_DATE))) == 0) {
-       cleanup_out_format(REC_TYPE_NORM, "%sDate: %s",
-                          cleanup_resent, mail_date(cleanup_time));
+    if ((state->headers_seen & (1 << (state->resent[0] ?
+                                     HDR_RESENT_DATE : HDR_DATE))) == 0) {
+       cleanup_out_format(state, REC_TYPE_NORM, "%sDate: %s",
+                          state->resent, mail_date(state->time));
     }
 
     /*
@@ -327,173 +337,161 @@ static void cleanup_missing_headers(void)
 #define NOT_SPECIAL_SENDER(addr) (*(addr) != 0 \
           && strcasecmp(addr, mail_addr_double_bounce()) != 0)
 
-    if ((cleanup_headers_seen & (1 << (cleanup_resent[0] ?
-                                      HDR_RESENT_FROM : HDR_FROM))) == 0) {
-       quote_822_local(cleanup_temp1, cleanup_sender);
-       vstring_sprintf(cleanup_temp2, "%sFrom: %s",
-                       cleanup_resent, vstring_str(cleanup_temp1));
-       if (cleanup_fullname && *cleanup_fullname) {
-           vstring_strcat(cleanup_temp2, " (");
-           token = tok822_alloc(TOK822_COMMENT, cleanup_fullname);
-           tok822_externalize(cleanup_temp2, token, TOK822_STR_NONE);
+    if ((state->headers_seen & (1 << (state->resent[0] ?
+                                     HDR_RESENT_FROM : HDR_FROM))) == 0) {
+       quote_822_local(state->temp1, state->sender);
+       vstring_sprintf(state->temp2, "%sFrom: %s",
+                       state->resent, vstring_str(state->temp1));
+       if (state->fullname && *state->fullname) {
+           vstring_strcat(state->temp2, " (");
+           token = tok822_alloc(TOK822_COMMENT, state->fullname);
+           tok822_externalize(state->temp2, token, TOK822_STR_NONE);
            tok822_free(token);
-           vstring_strcat(cleanup_temp2, ")");
+           vstring_strcat(state->temp2, ")");
        }
-       CLEANUP_OUT_BUF(REC_TYPE_NORM, cleanup_temp2);
-    } else if ((cleanup_headers_seen & (1 << (cleanup_resent[0] ?
+       CLEANUP_OUT_BUF(state, REC_TYPE_NORM, state->temp2);
+    } else if ((state->headers_seen & (1 << (state->resent[0] ?
                                      HDR_RESENT_SENDER : HDR_SENDER))) == 0
-              && NOT_SPECIAL_SENDER(cleanup_sender)) {
-       from = (cleanup_resent[0] ? cleanup_resent_from : cleanup_from);
-       if (from == 0 || strcasecmp(cleanup_sender, from) != 0) {
-           quote_822_local(cleanup_temp1, cleanup_sender);
-           cleanup_out_format(REC_TYPE_NORM, "%sSender: %s",
-                              cleanup_resent, vstring_str(cleanup_temp1));
+              && NOT_SPECIAL_SENDER(state->sender)) {
+       from = (state->resent[0] ? state->resent_from : state->from);
+       if (from == 0 || strcasecmp(state->sender, from) != 0) {
+           quote_822_local(state->temp1, state->sender);
+           cleanup_out_format(state, REC_TYPE_NORM, "%sSender: %s",
+                              state->resent, vstring_str(state->temp1));
        }
     }
 }
 
-/* cleanup_message - process message content segment */
+/* cleanup_message - initialize message content segment */
 
-void    cleanup_message(void)
+void    cleanup_message_init(CLEANUP_STATE *state, int type, char *buf, int len)
 {
-    char   *myname = "cleanup_message";
-    long    mesg_offset;
-    long    data_offset;
-    long    xtra_offset;
-    int     in_header;
-    char   *start;
-    int     type = 0;
+    char   *myname = "cleanup_message_init";
 
     /*
      * Write a dummy start-of-content segment marker. We'll update it with
      * real file offset information after reaching the end of the message
      * content.
      */
-    if ((mesg_offset = vstream_ftell(cleanup_dst)) < 0)
+    if ((state->mesg_offset = vstream_ftell(state->dst)) < 0)
        msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
-    cleanup_out_format(REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
-    if ((data_offset = vstream_ftell(cleanup_dst)) < 0)
+    cleanup_out_format(state, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, 0L);
+    if ((state->data_offset = vstream_ftell(state->dst)) < 0)
        msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
+    state->action = cleanup_message_header;
+    cleanup_message_header(state, type, buf, len);
+}
+
+/* cleanup_message_header - process message content, header */
+
+void    cleanup_message_header(CLEANUP_STATE *state, int type, char *buf, int len)
+{
+    char   *myname = "cleanup_message_header";
+
+    if (strchr(REC_TYPE_CONTENT, type) == 0) {
+       msg_warn("%s: %s: unexpected record type %d",
+                state->queue_id, myname, type);
+       state->errs |= CLEANUP_STAT_BAD;
+       return;
+    }
 
     /*
-     * An unannounced end-of-input condition most likely means that the
-     * client did not want to send this message after all. Don't complain,
-     * just stop generating any further output.
+     * First, deal with header information that we have accumulated from
+     * previous input records. A whole record that starts with whitespace is
+     * a continuation of previous data.
      * 
-     * XXX Rely on the front-end programs to enforce record size limits.
+     * XXX Silently switch to body processing when some message header requires
+     * an unreasonable amount of storage, or when a message header record
+     * does not fit in a REC_TYPE_NORM type record.
      */
-    in_header = 1;
-
-    while (CLEANUP_OUT_OK()) {
-
-       if ((type = rec_get(cleanup_src, cleanup_inbuf, 0)) < 0) {
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           break;
-       }
-       if (strchr(REC_TYPE_CONTENT, type) == 0) {
-           msg_warn("%s: %s: unexpected record type %d",
-                    cleanup_queue_id, myname, type);
-           cleanup_errs |= CLEANUP_STAT_BAD;
-           break;
+    if (VSTRING_LEN(state->header_buf) > 0) {
+       if ((VSTRING_LEN(state->header_buf) >= var_header_limit
+            || type != REC_TYPE_NORM)) {
+           state->errs |= CLEANUP_STAT_HOVFL;
+       } else if (ISSPACE(*buf)) {
+           VSTRING_ADDCH(state->header_buf, '\n');
+           vstring_strcat(state->header_buf, buf);
+           return;
        }
-       start = vstring_str(cleanup_inbuf);
 
        /*
-        * First, deal with header information that we have accumulated from
-        * previous input records. A whole record that starts with whitespace
-        * is a continuation of previous data.
-        * 
-        * XXX Silently switch to body processing when some message header
-        * requires an unreasonable amount of storage, or when a message
-        * header record does not fit in a REC_TYPE_NORM type record.
+        * No more input to append to this saved header. Do output processing
+        * and reset the saved header buffer.
         */
-       if (VSTRING_LEN(cleanup_header_buf) > 0) {
-           if (VSTRING_LEN(cleanup_header_buf) < var_header_limit
-               && type == REC_TYPE_NORM && ISSPACE(*start)) {
-               VSTRING_ADDCH(cleanup_header_buf, '\n');
-               vstring_strcat(cleanup_header_buf, start);
-               continue;
-           }
+       VSTRING_TERMINATE(state->header_buf);
+       cleanup_header(state);
+       VSTRING_RESET(state->header_buf);
+    }
 
-           /*
-            * No more input to append to this saved header. Do output
-            * processing and reset the saved header buffer.
-            */
-           VSTRING_TERMINATE(cleanup_header_buf);
-           cleanup_header();
-           VSTRING_RESET(cleanup_header_buf);
-       }
+    /*
+     * Switch to body processing if this is not a header or if the saved
+     * header would require an unreasonable amount of storage. Generate
+     * missing headers. Add one blank line when the message headers are
+     * immediately followed by a non-empty message body.
+     */
+    if (((state->errs & CLEANUP_STAT_HOVFL) || !is_header(buf))) {
+       cleanup_missing_headers(state);
+       if (type != REC_TYPE_XTRA && *buf)      /* output blank line */
+           cleanup_out_string(state, REC_TYPE_NORM, "");
+       state->action = cleanup_message_body;
+       cleanup_message_body(state, type, buf, len);
+    }
 
-       /*
-        * Switch to body processing if we didn't read a header or if the
-        * saved header requires an unreasonable amount of storage. Generate
-        * missing headers. Add one blank line when the message headers are
-        * immediately followed by a non-empty message body.
-        */
-       if (in_header
-           && (VSTRING_LEN(cleanup_header_buf) >= var_header_limit
-               || type != REC_TYPE_NORM
-               || !is_header(start))) {
-           in_header = 0;
-           cleanup_missing_headers();
-           if (type != REC_TYPE_XTRA && *start)/* output blank line */
-               cleanup_out_string(REC_TYPE_NORM, "");
-       }
+    /*
+     * Save this header record until we know that the header is complete.
+     */
+    else {
+       vstring_strcpy(state->header_buf, buf);
+    }
+}
 
-       /*
-        * If this is a header record, save it until we know that the header
-        * is complete. If this is a body record, copy it to the output
-        * immediately.
-        */
-       if (type == REC_TYPE_NORM || type == REC_TYPE_CONT) {
-           if (in_header) {
-               vstring_strcpy(cleanup_header_buf, start);
-           } else {
-               CLEANUP_OUT_BUF(type, cleanup_inbuf);
-           }
-       }
+/* cleanup_message_body - process message segment, body */
 
-       /*
-        * If we have reached the end of the message content segment, update
-        * the start-of-content marker, now that we know how large the
-        * message content segment is, and update the content size indicator
-        * at the beginning of the message envelope segment. vstream_fseek()
-        * implicitly flushes the stream, which may fail for various reasons.
-        */
-       else if (type == REC_TYPE_XTRA) {
-           if ((xtra_offset = vstream_ftell(cleanup_dst)) < 0)
-               msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
-           if (vstream_fseek(cleanup_dst, mesg_offset, SEEK_SET) < 0) {
-               msg_warn("%s: write queue file: %m", cleanup_queue_id);
-               if (errno == EFBIG)
-                   cleanup_errs |= CLEANUP_STAT_SIZE;
-               else
-                   cleanup_errs |= CLEANUP_STAT_WRITE;
-               break;
-           }
-           cleanup_out_format(REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, xtra_offset);
-           if (vstream_fseek(cleanup_dst, 0L, SEEK_SET) < 0)
-               msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
-           cleanup_out_format(REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
-                              xtra_offset - data_offset);
-           if (vstream_fseek(cleanup_dst, xtra_offset, SEEK_SET) < 0)
-               msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
-           break;
-       }
+void    cleanup_message_body(CLEANUP_STATE *state, int type, char *buf, int len)
+{
+    char   *myname = "cleanup_message_body";
+    long    xtra_offset;
 
-       /*
-        * This should never happen.
-        */
-       else {
-           msg_panic("%s: unexpected record type: %d", myname, type);
+    /*
+     * Copy body record to the output.
+     */
+    if (type == REC_TYPE_NORM || type == REC_TYPE_CONT) {
+       cleanup_out(state, type, buf, len);
+    }
+
+    /*
+     * If we have reached the end of the message content segment, update the
+     * start-of-content marker, now that we know how large the message
+     * content segment is, and update the content size indicator at the
+     * beginning of the message envelope segment. vstream_fseek() implicitly
+     * flushes the stream, which may fail for various reasons.
+     */
+    else if (type == REC_TYPE_XTRA) {
+       if ((xtra_offset = vstream_ftell(state->dst)) < 0)
+           msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
+       if (vstream_fseek(state->dst, state->mesg_offset, SEEK_SET) < 0) {
+           msg_warn("%s: write queue file: %m", state->queue_id);
+           if (errno == EFBIG)
+               state->errs |= CLEANUP_STAT_SIZE;
+           else
+               state->errs |= CLEANUP_STAT_WRITE;
+           return;
        }
+       cleanup_out_format(state, REC_TYPE_MESG, REC_TYPE_MESG_FORMAT, xtra_offset);
+       if (vstream_fseek(state->dst, 0L, SEEK_SET) < 0)
+           msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
+       cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
+                          xtra_offset - state->data_offset);
+       if (vstream_fseek(state->dst, xtra_offset, SEEK_SET) < 0)
+           msg_fatal("%s: vstream_fseek %s: %m", myname, cleanup_path);
+       state->action = cleanup_extracted_init;
     }
 
     /*
-     * Keep reading in case of problems, so that the sender is ready to
-     * receive our status report.
+     * This should never happen.
      */
-    if (CLEANUP_OUT_OK() == 0)
-       if (type >= 0)
-           cleanup_skip();
+    else {
+       msg_warn("%s: unexpected record type: %d", myname, type);
+       state->errs |= CLEANUP_STAT_BAD;
+    }
 }
index 7be237040813e84a5a6b8100b78f9b0f8efb2b3d..aa9618dcc8ae3f1335d0b969f38d4cd252287954 100644 (file)
@@ -6,22 +6,27 @@
 /* SYNOPSIS
 /*     #include "cleanup.h"
 /*
-/*     int     CLEANUP_OUT_OK()
+/*     int     CLEANUP_OUT_OK(state)
+/*     CLEANUP_STATE *state;
 /*
-/*     void    cleanup_out(type, data, len)
+/*     void    cleanup_out(state, type, data, len)
+/*     CLEANUP_STATE *state;
 /*     int     type;
 /*     char    *data;
 /*     int     len;
 /*
-/*     void    cleanup_out_string(type, str)
+/*     void    cleanup_out_string(state, type, str)
+/*     CLEANUP_STATE *state;
 /*     int     type;
 /*     char    *str;
 /*
-/*     void    CLEANUP_OUT_BUF(type, buf)
+/*     void    CLEANUP_OUT_BUF(state, type, buf)
+/*     CLEANUP_STATE *state;
 /*     int     type;
 /*     VSTRING *buf;
 /*
-/*     void    cleanup_out_format(type, format, ...)
+/*     void    cleanup_out_format(state, type, format, ...)
+/*     CLEANUP_STATE *state;
 /*     int     type;
 /*     char    *format;
 /* DESCRIPTION
@@ -57,7 +62,7 @@
 
 #include <sys_defs.h>
 #include <errno.h>
-#include <stdlib.h>            /* 44BSD stdarg.h uses abort() */
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
 #include <stdarg.h>
 #include <string.h>
 
 
 /* cleanup_out - output one single record */
 
-void    cleanup_out(int type, char *string, int len)
+void    cleanup_out(CLEANUP_STATE *state, int type, char *string, int len)
 {
-    if (CLEANUP_OUT_OK()) {
-       if (rec_put(cleanup_dst, type, string, len) < 0) {
+    if (CLEANUP_OUT_OK(state)) {
+       if (rec_put(state->dst, type, string, len) < 0) {
            if (errno == EFBIG) {
                msg_warn("%s: queue file size limit exceeded",
-                        cleanup_queue_id);
-               cleanup_errs |= CLEANUP_STAT_SIZE;
+                        state->queue_id);
+               state->errs |= CLEANUP_STAT_SIZE;
            } else {
-               msg_warn("%s: write queue file: %m", cleanup_queue_id);
-               cleanup_errs |= CLEANUP_STAT_WRITE;
+               msg_warn("%s: write queue file: %m", state->queue_id);
+               state->errs |= CLEANUP_STAT_WRITE;
            }
        }
     }
@@ -97,14 +102,14 @@ void    cleanup_out(int type, char *string, int len)
 
 /* cleanup_out_string - output string to one single record */
 
-void    cleanup_out_string(int type, char *string)
+void    cleanup_out_string(CLEANUP_STATE *state, int type, char *string)
 {
-    cleanup_out(type, string, strlen(string));
+    cleanup_out(state, type, string, strlen(string));
 }
 
 /* cleanup_out_format - output one formatted record */
 
-void    cleanup_out_format(int type, char *fmt,...)
+void    cleanup_out_format(CLEANUP_STATE *state, int type, char *fmt,...)
 {
     static VSTRING *vp;
     va_list ap;
@@ -114,5 +119,5 @@ void    cleanup_out_format(int type, char *fmt,...)
     va_start(ap, fmt);
     vstring_vsprintf(vp, fmt, ap);
     va_end(ap);
-    CLEANUP_OUT_BUF(type, vp);
+    CLEANUP_OUT_BUF(state, type, vp);
 }
index 596e172582f2580cdf35b49ac4d6970af71b9348..ff4450ed19a76eb54a2a993ef35c8ead158c34fe 100644 (file)
@@ -6,7 +6,8 @@
 /* SYNOPSIS
 /*     #include "cleanup.h"
 /*
-/*     void    cleanup_out_recipient(recipient)
+/*     void    cleanup_out_recipient(state, recipient)
+/*     CLEANUP_STATE *state;
 /*     char    *recipient;
 /* DESCRIPTION
 /*     This module implements an envelope recipient output filter.
 
 /* cleanup_out_recipient - envelope recipient output filter */
 
-void    cleanup_out_recipient(char *recip)
+void    cleanup_out_recipient(CLEANUP_STATE *state, char *recip)
 {
     ARGV   *argv;
     char  **cpp;
 
     if (cleanup_virtual_maps == 0) {
-       if (been_here_fixed(cleanup_dups, recip) == 0)
-           cleanup_out_string(REC_TYPE_RCPT, recip);
+       if (been_here_fixed(state->dups, recip) == 0)
+           cleanup_out_string(state, REC_TYPE_RCPT, recip);
     } else {
-       argv = cleanup_map1n_internal(recip, cleanup_virtual_maps,
+       argv = cleanup_map1n_internal(state, recip, cleanup_virtual_maps,
                                  cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
        for (cpp = argv->argv; *cpp; cpp++)
-           if (been_here_fixed(cleanup_dups, *cpp) == 0)
-               cleanup_out_string(REC_TYPE_RCPT, *cpp);
+           if (been_here_fixed(state->dups, *cpp) == 0)
+               cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
        argv_free(argv);
     }
 }
diff --git a/postfix/cleanup/cleanup_skip.c b/postfix/cleanup/cleanup_skip.c
deleted file mode 100644 (file)
index a5ace49..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*++
-/* NAME
-/*     cleanup_skip 3
-/* SUMMARY
-/*     skip further input
-/* SYNOPSIS
-/*     #include "cleanup.h"
-/*
-/*     void    cleanup_skip(void)
-/* DESCRIPTION
-/*     cleanup_skip() skips client input. This function is used after
-/*     detecting an error. The idea is to drain input from the client
-/*     so the client is ready to read the cleanup service status report.
-/* 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>
-
-/* Global library. */
-
-#include <cleanup_user.h>
-#include <record.h>
-#include <rec_type.h>
-
-/* Application-specific. */
-
-#include "cleanup.h"
-
-/* cleanup_skip - skip further client input */
-
-void    cleanup_skip(void)
-{
-    int     type;
-
-    if ((cleanup_errs & CLEANUP_STAT_CONT) == 0)
-       msg_warn("%s: skipping further client input", cleanup_queue_id);
-
-    /*
-     * XXX Rely on the front-end programs to enforce record size limits.
-     */
-    while ((type = rec_get(cleanup_src, cleanup_inbuf, 0)) > 0
-          && type != REC_TYPE_END)
-        /* void */ ;
-}
index fe73981e12ca830262e51331dbaa8e6bc4db34a4..97e41d9b329166a760998b91777a1f73b7420232 100644 (file)
@@ -6,16 +6,14 @@
 /* SYNOPSIS
 /*     #include "cleanup.h"
 /*
-/*     void    cleanup_state_alloc(void)
+/*     CLEANUP_STATE *cleanup_state_alloc(void)
 /*
-/*     void    cleanup_state_free(void)
+/*     void    cleanup_state_free(state)
+/*     CLEANUP_STATE *state;
 /* DESCRIPTION
-/*     This module maintains about two dozen global (ugh) state variables
+/*     This module maintains about two dozen state variables
 /*     that are used by many routines in the course of processing one
-/*     message. Using globals seems to make more sense than passing around
-/*     large parameter lists, or passing around a structure with a large
-/*     number of components. We can get away with this because we need only
-/*     one instance at a time.
+/*     message.
 /*
 /*     cleanup_state_alloc() initializes the per-message state variables.
 /*
@@ -39,7 +37,7 @@
 
 #include <mymalloc.h>
 #include <vstring.h>
-#include <vstream.h>
+#include <argv.h>
 
 /* Global library. */
 
 
 #include "cleanup.h"
 
- /*
-  * These variables are accessed by many functions, and there is only one
-  * instance of each. Rather than passing around lots and lots of parameters,
-  * or passing them around in a structure, we just make the variables global,
-  * because that is what they are.
-  */
-VSTRING *cleanup_inbuf;                        /* read buffer */
-VSTRING *cleanup_temp1;                        /* scratch buffer, local use only */
-VSTRING *cleanup_temp2;                        /* scratch buffer, local use only */
-VSTREAM *cleanup_src;                  /* current input stream */
-VSTREAM *cleanup_dst;                  /* current output stream */
-MAIL_STREAM *cleanup_handle;           /* mail stream handle */
-char   *cleanup_queue_id;              /* queue file basename */
-time_t  cleanup_time;                  /* posting time */
-char   *cleanup_fullname;              /* envelope sender full name */
-char   *cleanup_sender;                        /* envelope sender address */
-char   *cleanup_from;                  /* From: address */
-char   *cleanup_resent_from;           /* Resent-From: address */
-char   *cleanup_recip;                 /* envelope recipient address */
-char   *cleanup_return_receipt;                /* return-receipt address */
-char   *cleanup_errors_to;             /* errors-to address */
-int     cleanup_flags;                 /* processing options */
-int     cleanup_errs;                  /* any badness experienced */
-int     cleanup_err_mask;              /* allowed badness */
-VSTRING *cleanup_header_buf;           /* multi-record header */
-int     cleanup_headers_seen;          /* which headers were seen */
-int     cleanup_hop_count;             /* count of received: headers */
-ARGV   *cleanup_recipients;            /* recipients from regular headers */
-ARGV   *cleanup_resent_recip;          /* recipients from resent headers */
-char   *cleanup_resent;                        /* any resent- header seen */
-BH_TABLE *cleanup_dups;                        /* recipient dup filter */
-
 /* cleanup_state_alloc - initialize global state */
 
-void    cleanup_state_alloc(void)
+CLEANUP_STATE *cleanup_state_alloc(void)
 {
-    cleanup_hop_count = 0;
-    cleanup_headers_seen = 0;
-    cleanup_time = 0;
-    cleanup_errs = 0;
-    cleanup_from = 0;
-    cleanup_fullname = 0;
-    cleanup_header_buf = vstring_alloc(100);
-    cleanup_queue_id = 0;
-    cleanup_recip = 0;
-    cleanup_return_receipt = 0;
-    cleanup_errors_to = 0;
-    cleanup_recipients = argv_alloc(2);
-    cleanup_resent = "";
-    cleanup_resent_from = 0;
-    cleanup_resent_recip = argv_alloc(2);
-    cleanup_sender = 0;
-    cleanup_temp1 = vstring_alloc(10);
-    cleanup_temp2 = vstring_alloc(10);
-    cleanup_inbuf = vstring_alloc(100);
-    cleanup_dups = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD);
+    CLEANUP_STATE *state = (CLEANUP_STATE *) mymalloc(sizeof(*state));
+
+    state->temp1 = vstring_alloc(10);
+    state->temp2 = vstring_alloc(10);
+    state->hop_count = 0;
+    state->headers_seen = 0;
+    state->time = 0;
+    state->errs = 0;
+    state->from = 0;
+    state->fullname = 0;
+    state->header_buf = vstring_alloc(100);
+    state->queue_id = 0;
+    state->recip = 0;
+    state->return_receipt = 0;
+    state->errors_to = 0;
+    state->recipients = argv_alloc(2);
+    state->resent = "";
+    state->resent_from = 0;
+    state->resent_recip = argv_alloc(2);
+    state->sender = 0;
+    state->dups = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD);
+    state->warn_time = 0;
+    state->action = cleanup_envelope_init;
+
+    return (state);
 }
 
 /* cleanup_state_free - destroy global state */
 
-void    cleanup_state_free(void)
+void    cleanup_state_free(CLEANUP_STATE *state)
 {
-    if (cleanup_fullname)
-       myfree(cleanup_fullname);
-    if (cleanup_sender)
-       myfree(cleanup_sender);
-    if (cleanup_from)
-       myfree(cleanup_from);
-    if (cleanup_resent_from)
-       myfree(cleanup_resent_from);
-    if (cleanup_recip)
-       myfree(cleanup_recip);
-    if (cleanup_return_receipt)
-       myfree(cleanup_return_receipt);
-    if (cleanup_errors_to)
-       myfree(cleanup_errors_to);
-    vstring_free(cleanup_header_buf);
-    argv_free(cleanup_recipients);
-    argv_free(cleanup_resent_recip);
-    vstring_free(cleanup_temp1);
-    vstring_free(cleanup_temp2);
-    vstring_free(cleanup_inbuf);
-    if (cleanup_queue_id)
-       myfree(cleanup_queue_id);
-    been_here_free(cleanup_dups);
+    vstring_free(state->temp1);
+    vstring_free(state->temp2);
+    if (state->fullname)
+       myfree(state->fullname);
+    if (state->sender)
+       myfree(state->sender);
+    if (state->from)
+       myfree(state->from);
+    if (state->resent_from)
+       myfree(state->resent_from);
+    if (state->recip)
+       myfree(state->recip);
+    if (state->return_receipt)
+       myfree(state->return_receipt);
+    if (state->errors_to)
+       myfree(state->errors_to);
+    vstring_free(state->header_buf);
+    argv_free(state->recipients);
+    argv_free(state->resent_recip);
+    if (state->queue_id)
+       myfree(state->queue_id);
+    been_here_free(state->dups);
+    myfree((char *) state);
 }
index 0eeb4e4b09da0ee9768ee2b0397b44e940f73508..6763727fc3d53e0d5af57d27c4c299fa62df2cc2 100644 (file)
@@ -128,7 +128,7 @@ mail_owner = postfix
 # FOR THIS TO WORK, DO NOT SPECIFY VIRTUAL DOMAINS IN MYDESTINATION.
 # MYDESTINATION MUST LIST NON-VIRTUAL DOMAINS ONLY.
 #
-#local_recipient_maps = $relocated_maps $alias_maps unix:passwd.byname
+#local_recipient_maps = $alias_maps unix:passwd.byname
 
 # ADDRESS REWRITING
 #
@@ -325,13 +325,11 @@ mail_owner = postfix
 # SHOW SOFTWARE VERSION OR NOT
 #
 # The smtpd_banner parameter specifies the text that follows the 220
-# status code in the SMTP greeting banner. Some people like to see
+# code in the SMTP server's greeting banner. Some people like to see
 # the mail version advertised. By default, Postfix shows no version.
 #
-# You MUST specify the $myhostname at the start of the text. When
-# the SMTP client sees its own hostname at the start of an SMTP
-# greeting banner it will report a mailer loop. That's better than
-# having a machine meltdown.
+# You MUST specify $myhostname at the start of the text. That is an
+# RFC requirement. Postfix itself does not care.
 #
 #smtpd_banner = $myhostname ESMTP $mail_name
 #smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
diff --git a/postfix/conf/pcre_table b/postfix/conf/pcre_table
new file mode 100644 (file)
index 0000000..cdecf78
--- /dev/null
@@ -0,0 +1 @@
+THIS IS TODO
diff --git a/postfix/conf/regexp_table b/postfix/conf/regexp_table
new file mode 100644 (file)
index 0000000..cdecf78
--- /dev/null
@@ -0,0 +1 @@
+THIS IS TODO
index 5bc62a6bdb8b0a7754677f7df5f4ba1a05e4e91a..940ef40b858a4788c1a0a7bf0972a2b676541650 100644 (file)
@@ -51,6 +51,8 @@ local_transport = local
 # ${name:value} to expand value only when $name does (does not) exist.
 #
 #forward_path = /var/forward/$user
+#forward_path = /var/forward/$user/.forward$recipient_delimiter$extension,
+#      /var/forward/$user/.forward
 forward_path = $home/.forward$recipient_delimiter$extension,$home/.forward
 
 # The allow_mail_to_commands parameter restricts mail delivery to
index e5e6def483c5d3e93db121617a6363d9b0a9d388..122652d692abad91c23a589903fd10e7dae69340 100644 (file)
 /*     const char *queue;
 /*     const char *id;
 /*     const char *sender;
+/*
+/*     int     bounce_recip(flags, queue, id, sender, recipient, relay,
+/*                                     entry, format, ...)
+/*     int     flags;
+/*     const char *queue;
+/*     const char *id;
+/*     const char *sender;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *format;
+/*
+/*     int     vbounce_recip(flags, queue, id, sender, recipient, relay,
+/*                                     entry, format, ap)
+/*     int     flags;
+/*     const char *queue;
+/*     const char *id;
+/*     const char *sender;
+/*     const char *recipient;
+/*     const char *relay;
+/*     time_t  entry;
+/*     const char *format;
+/*     va_list ap;
 /* DESCRIPTION
 /*     This module implements the client interface to the message
 /*     bounce service, which maintains a per-message log of status
 /*     the specified sender, including the bounce log that was
 /*     built with bounce_append().
 /*
+/*     bounce_recip() and vbounce_recipient() send one bounce
+/*     message immediately, without accessing a per-message bounce file.
+/*
 /*     Arguments:
 /* .IP flags
-/*     The bitwise OR of zero or mor of the following (specify
+/*     The bitwise OR of zero or more of the following (specify
 /*     BOUNCE_FLAG_NONE to request no special processing):
 /* .RS
 /* .IP BOUNCE_FLAG_CLEAN
 /*     Delete the bounce log in case of an error (as in: pretend
 /*     that we never even tried to bounce this message).
-/* .IP BOUNCE_FLAG_COPY
-/*     Request that a postmaster copy is sent (bounce_flush() only).
 /* .RE
 /* .IP queue
 /*     The message queue name of the original message file.
@@ -185,3 +209,61 @@ int     bounce_flush(int flags, const char *queue, const char *id,
        return (-1);
     }
 }
+
+/* bounce_recip - send bounce for one recipient */
+
+int     bounce_recip(int flags, const char *queue, const char *id,
+                            const char *sender, const char *recipient,
+                            const char *relay, time_t entry,
+                            const char *fmt,...)
+{
+    va_list ap;
+    int     status;
+
+    va_start(ap, fmt);
+    status = vbounce_recip(flags, queue, id, sender, recipient, relay,
+                          entry, fmt, ap);
+    va_end(ap);
+    return (status);
+}
+
+/* vbounce_recip - send bounce for one recipient */
+
+int     vbounce_recip(int flags, const char *queue, const char *id,
+                             const char *sender, const char *recipient,
+                             const char *relay, time_t entry,
+                             const char *fmt, va_list ap)
+{
+    VSTRING *why;
+    int     status;
+    int     delay;
+
+    /*
+     * When we're pretending that we can't bounce, don't create a defer log
+     * file when we wouldn't keep the bounce log file. That's a lot of
+     * negatives in one sentence.
+     */
+    if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN))
+       return (-1);
+
+    delay = time((time_t *) 0) - entry;
+    why = vstring_alloc(100);
+    vstring_vsprintf(why, fmt, ap);
+    if (mail_command_write(MAIL_CLASS_PRIVATE, var_soft_bounce ?
+                          MAIL_SERVICE_DEFER : MAIL_SERVICE_BOUNCE,
+                          "%d %d %s %s %s %s %s", BOUNCE_CMD_RECIP,
+                          flags, queue, id, sender, recipient,
+                          vstring_str(why)) == 0) {
+       msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s)",
+                id, recipient, relay, delay, var_soft_bounce ? "deferred" :
+                "bounced", vstring_str(why));
+       status = (var_soft_bounce ? -1 : 0);
+    } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
+       status = defer_append(flags, id, recipient, "bounce", delay,
+                             "bounce failed");
+    } else {
+       status = -1;
+    }
+    vstring_free(why);
+    return (status);
+}
index c1316b26c03eea12df1daf0f0de5a3e016420f7a..632d62fb015875e513030d64bdd70a8e2aaeaab7 100644 (file)
@@ -26,20 +26,27 @@ extern int vbounce_append(int, const char *, const char *, const char *,
                                  time_t, const char *, va_list);
 extern int bounce_flush(int, const char *, const char *, const char *);
 
+extern int bounce_recip(int, const char *, const char *, const char *,
+                               const char *, const char *, time_t,
+                               const char *,...);
+extern int vbounce_recip(int, const char *, const char *, const char *,
+                                const char *, const char *, time_t,
+                                const char *, va_list);
+
  /*
   * Bounce/defer protocol commands.
   */
 #define BOUNCE_CMD_APPEND      0       /* append log */
 #define BOUNCE_CMD_FLUSH       1       /* send log */
-#define BOUNCE_CMD_WARN                2       /* send warning bounce, don't delete log */
+#define BOUNCE_CMD_WARN                2       /* send warning bounce, don't delete
+                                        * log */
+#define BOUNCE_CMD_RECIP       3       /* immediate bounce, no logfile */
 
  /*
   * Flags.
   */
 #define BOUNCE_FLAG_NONE       0       /* no flags up */
 #define BOUNCE_FLAG_CLEAN      (1<<0)  /* remove log on error */
-#define BOUNCE_FLAG_COPY       (1<<1)  /* postmaster notice */
-#define BOUNCE_FLAG_VERP       (1<<2)  /* personalized bounce */
 
  /*
   * Backwards compatibility.
index cd23b4d7a5ef40e37d939c2d7f95f01843cb6056..088f31aaa97150551b06a9509c6d566f661d2132 100644 (file)
@@ -39,7 +39,8 @@
  /*
   * Mapping from status code to printable string. One message may suffer from
   * multiple errors, to it is important to list the most severe errors first,
-  * because the result of lookup can be only one string.
+  * or to list the cause (header overflow) before the effect (no recipients),
+  * because cleanup_strerror() can report only one error.
   */
 struct cleanup_stat_map {
     unsigned status;
@@ -48,6 +49,7 @@ struct cleanup_stat_map {
 
 static struct cleanup_stat_map cleanup_stat_map[] = {
     CLEANUP_STAT_BAD, "Internal protocol error",
+    CLEANUP_STAT_HOVFL, "Message header too long",
     CLEANUP_STAT_RCPT, "No recipients specified",
     CLEANUP_STAT_HOPS, "Too many hops",
     CLEANUP_STAT_SIZE, "Message file too big",
index ed28005e93214ac68cde0bb9f895fa26e7995917..cc7d768e47ed700d307efa1349e14ef7ddd4acb0 100644 (file)
@@ -31,6 +31,9 @@
 #define CLEANUP_STAT_HOPS      (1<<4)  /* Too many hops */
 #define CLEANUP_STAT_SYN       (1<<5)  /* Bad address syntax */
 #define CLEANUP_STAT_RCPT      (1<<6)  /* No recipients found */
+#define CLEANUP_STAT_HOVFL     (1<<7)  /* Header overflow */
+
+#define CLEANUP_STAT_LETHAL    (~CLEANUP_STAT_HOVFL)   /* lethal errors */
 
 extern const char *cleanup_strerror(unsigned);
 
index f59e41ccbe6ee18af6f89b8e062538ce9142451f..70735497a73f21635ae77141d8e5c246e6c1c929 100644 (file)
@@ -60,8 +60,6 @@
 /* .IP BOUNCE_FLAG_CLEAN
 /*     Delete the defer log in case of an error (as in: pretend
 /*     that we never even tried to defer this message).
-/* .IP BOUNCE_FLAG_COPY
-/*     Request that postmaster a copy is sent (defer_flush() only).
 /* .RE
 /* .IP queue
 /*     The message queue name of the original message file.
index 508acbf02a2f6c1c944ca4150f197770aa0a8998..d7f309d68d9fa120fdf6e23f78a8fc88555fe65b 100644 (file)
@@ -420,6 +420,7 @@ extern int var_delay_warn_time;
 
 #define VAR_QMGR_ACT_LIMIT     "qmgr_message_active_limit"
 #define DEF_QMGR_ACT_LIMIT     1000
+extern int var_qmgr_active_limit;
 
 #define VAR_QMGR_RCPT_LIMIT    "qmgr_message_recipient_limit"
 #define DEF_QMGR_RCPT_LIMIT    10000
@@ -429,6 +430,10 @@ extern int var_qmgr_rcpt_limit;
 #define DEF_QMGR_FUDGE         100
 extern int var_qmgr_fudge;
 
+#define VAR_QMGR_HOG           "qmgr_site_hog_factor"
+#define DEF_QMGR_HOG           90
+extern int var_qmgr_hog;
+
  /*
   * Queue manager: default destination concurrency levels.
   */
@@ -437,6 +442,7 @@ extern int var_qmgr_fudge;
 extern int var_init_dest_concurrency;
 
 #define VAR_DEST_CON_LIMIT     "default_destination_concurrency_limit"
+#define _DEST_CON_LIMIT                "_destination_concurrency_limit"
 #define DEF_DEST_CON_LIMIT     10
 extern int var_dest_con_limit;
 
@@ -444,9 +450,13 @@ extern int var_dest_con_limit;
   * Queue manager: default number of recipients per transaction.
   */
 #define VAR_DEST_RCPT_LIMIT    "default_destination_recipient_limit"
+#define _DEST_RCPT_LIMIT       "_destination_recipient_limit"
 #define DEF_DEST_RCPT_LIMIT    50
 extern int var_dest_rcpt_limit;
 
+#define VAR_LOCAL_RCPT_LIMIT   "local" _DEST_RCPT_LIMIT        /* XXX */
+#define DEF_LOCAL_RCPT_LIMIT   1       /* XXX */
+
  /*
   * Queue manager: default delay before retrying a dead transport.
   */
index 4cde268e7eb4b5591e025168c467f21a6882e852..310798d71347dbaae1a32f74a41f0bbbb1b4e548 100644 (file)
@@ -299,6 +299,7 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
     int     fd;
     const char *file_id;
     VSTREAM *stream;
+    int     count;
 
     /*
      * Initialize.
@@ -349,10 +350,10 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
     file_id = get_file_id(fd);
     GETTIMEOFDAY(&tv);
 
-    for (;;) {
+    for (count = 0;; count++) {
        vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
        mail_queue_path(path_buf, queue_name, STR(id_buf));
-       if (rename(STR(temp_path), STR(path_buf)) == 0) /* success */
+       if (sane_rename(STR(temp_path), STR(path_buf)) == 0)    /* success */
            break;
        if (errno == EPERM || errno == EISDIR) {/* collision. weird. */
            if ((int) ++tv.tv_usec < 0)
@@ -362,8 +363,10 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
        if (errno != ENOENT || mail_queue_mkdirs(STR(path_buf)) < 0) {
            msg_warn("%s: rename %s to %s: %m", myname,
                     STR(temp_path), STR(path_buf));
-           sleep(10);
        }
+       if (count > 1000)                       /* XXX whatever */
+           msg_fatal("%s: rename %s to %s: giving up", myname,
+                     STR(temp_path), STR(path_buf));
     }
 
     stream = vstream_fdopen(fd, O_RDWR);
index dc50b79d469722db710e875a827f6df532d49416..5cccad7e62ce84463081cfc45f23ad08ebd61c10 100644 (file)
@@ -15,7 +15,7 @@
   * Version of this program.
   */
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "Snapshot-20000104"
+#define DEF_MAIL_VERSION       "Snapshot-20000129"
 extern char *var_mail_version;
 
 /* LICENSE
index 70cbbba4afc60816511cafdc326c8055a60c1a40..5354ad333533158b3fa2963ac7bda4ca256ac05b 100644 (file)
@@ -8,7 +8,7 @@ COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
        postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
        postsuper.1.html
 CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \
-       transport.5.html virtual.5.html
+       transport.5.html virtual.5.html pcre_table.5.html regexp_table.5.html
 
 update:        $(DAEMONS) $(COMMANDS) $(CONFIG)
 
@@ -113,6 +113,12 @@ aliases.5.html: ../conf/aliases
 canonical.5.html: ../conf/canonical
        srctoman - $? | nroff -man | man2html | postlink >$@
 
+pcre_table.5.html: ../conf/pcre_table
+       srctoman - $? | nroff -man | man2html | postlink >$@
+
+regexp_table.5.html: ../conf/regexp_table
+       srctoman - $? | nroff -man | man2html | postlink >$@
+
 relocated.5.html: ../conf/relocated
        srctoman - $? | nroff -man | man2html | postlink >$@
 
index 78284a568f54c53dfa1b68c750ad51b940b96140..3c0de66f957495ef83e8502e6fac947bf2adcabb 100644 (file)
@@ -17,12 +17,23 @@ ACCESS(5)                                               ACCESS(5)
        hosts,   domains,   networks,   host   addresses  or  mail
        addresses.
 
-       The table serves as input to the <a href="postmap.1.html"><b>postmap</b>(1)</a>  command.  The
-       result,  an  indexed file in <b>dbm</b> or <b>db</b> format, is used for
-       fast searching by the mail system. After an update it  may
-       take  a  minute  or  so before the change becomes visible.
-       Issue a <b>postfix</b> <b>reload</b> command to eliminate the delay.
-
+       Normally, the table serves as input to the <a href="postmap.1.html"><b>postmap</b>(1)</a> com-
+       mand.  The result, an indexed file in <b>dbm</b> or <b>db</b> format, is
+       used for fast searching  by  the  mail  system.  After  an
+       update  it  may  take  a  minute  or  so before the change
+       becomes visible.  Issue a <b>postfix</b> <b>reload</b> command to elimi-
+       nate the delay.
+
+       When  the  table  is provided via other means such as NIS,
+       LDAP or SQL, the same lookups are  done  as  for  ordinary
+       indexed files.
+
+       Alternatively,  the  table  can  be provided as a regular-
+       expression map where patterns are given as regular expres-
+       sions.  In  that  case, the lookups are done in a slightly
+       different way as described below.
+
+<b>TABLE</b> <b>FORMAT</b>
        The format of the access table is as follows:
 
        blanks and comments
@@ -34,45 +45,45 @@ ACCESS(5)                                               ACCESS(5)
               address, perform the corresponding <i>action</i>.
 
 <b>PATTERNS</b>
-       Patterns are tried in the order as listed below:
+       With lookups from indexed files, patterns are tried in the
+       order as listed below:
 
        <i>user</i>@<i>domain</i>
               Matches the specified mail address.
 
        <i>domain.name</i>
-              Matches the <i>domain.name</i> itself  and  any  subdomain
-              thereof,  either in hostnames or in mail addresses.
+              Matches  the  <i>domain.name</i>  itself and any subdomain
+              thereof, either in hostnames or in mail  addresses.
               Top-level domains will never be matched.
 
-       <i>user</i>@  Matches all mail addresses with the specified  user
+       <i>user</i>@  Matches  all mail addresses with the specified user
               part.
 
-       <i>net.work.addr.ess</i>
 
-       <i>net.work.addr</i>
 
-       <i>net.work</i>
 
-       <i>net</i>    Matches  any host address in the specified network.
-              A network address is a  sequence  of  one  or  more
-              octets separated by ".".
-
-<b>ACTIONS</b>
+                                                                1
 
 
 
 
-                                                                1
 
+ACCESS(5)                                               ACCESS(5)
 
 
+       <i>net.work.addr.ess</i>
 
+       <i>net.work.addr</i>
 
-ACCESS(5)                                               ACCESS(5)
+       <i>net.work</i>
 
+       <i>net</i>    Matches any host address in the specified  network.
+              A  network  address  is  a  sequence of one or more
+              octets separated by ".".
 
+<b>ACTIONS</b>
        [<b>45</b>]<i>XX</i> <i>text</i>
-              Reject  the  address etc. that matches the pattern,
+              Reject the address etc. that matches  the  pattern,
               and respond with the numerical code and text.
 
        <b>REJECT</b> Reject the address etc. that matches the pattern. A
@@ -83,16 +94,50 @@ ACCESS(5)                                               ACCESS(5)
        <i>Any</i> <i>other</i> <i>text</i>
               Accept the address etc. that matches the pattern.
 
+<b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b>
+       This section describes how the table lookups  change  when
+       the table is given in the form of regular expressions. For
+       a description of regular expression lookup  table  syntax,
+       see <b>regexp</b><i>_</i><b>table</b>(5) or <b>pcre</b><i>_</i><b>table</b>(5).
+
+       Patterns  become  regular  expressions that are applied to
+       the entire string being looked up. Depending on the appli-
+       cation,  that  string  is  an  entire  client hostname, an
+       entire client IP address, or an entire mail address.
+
+       In contrast to the normal lookups from indexed  files,  no
+       parent  domain  or network search is done, and <i>user@domain</i>
+       mail addresses are not broken  up  into  their  <i>user@</i>  and
+       <i>domain</i> constituent parts.
+
+       Actions  are the same as with normal indexed file lookups,
+       with the additional feature that parenthesized  substrings
+       from  the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
+
 <b>BUGS</b>
-       The  table format does not understand quoting conventions.
+       The table format does not understand quoting  conventions.
 
 <b>SEE</b> <b>ALSO</b>
        <a href="postmap.1.html">postmap(1)</a> create mapping table
        <a href="smtpd.8.html">smtpd(8)</a> smtp server
+       pcre_table(5) format of PCRE tables
+       regexp_table(5) format of POSIX regexp tables
 
 <b>LICENSE</b>
-       The Secure Mailer license must  be  distributed  with
-       this software.
+       The  Secure  Mailer  license must be distributed with this
+
+
+
+                                                                2
+
+
+
+
+
+ACCESS(5)                                               ACCESS(5)
+
+
+       software.
 
 <b>AUTHOR(S)</b>
        Wietse Venema
@@ -128,7 +173,28 @@ ACCESS(5)                                               ACCESS(5)
 
 
 
-                                                                2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                3
 
 
 </pre> </body> </html>
index 50bfd4f294d264d1ce635f47b5b08354d65a3b6e..f26e92faeba45614cdb7f674d70722b8991fc041 100644 (file)
@@ -26,6 +26,8 @@
 
 <li><a href="#sendmail_incompatibility">Sendmail incompatibility</a>
 
+<li><a href="#receiving">Receiving mail via the network</a>
+
 <li><a href="#relaying">Mail relaying</a>
 
 <li><a href="#remote_delivery">Remote delivery</a>
@@ -89,6 +91,17 @@ distribution list</a>
 
 <li><a href="#skip_greeting">Postfix does not try all the MX addresses</a>
 
+<li><a href="#worm">Postfix accepts MAIL FROM and RCPT TO "| command"</a>
+
+</ul>
+
+<a name="receiving"><h3>Receiving mail via the network</h3>
+
+<ul>
+
+<li><a href="#numerical_log">Postfix logs SMTP clients as IP
+addresses</a>
+
 </ul>
 
 <a name="relaying"><h3>Mail relaying</h3>
@@ -663,7 +676,7 @@ four hours, specify:
 
 <pre>
     /etc/postfix/main.cf:
-       delay_warning_time = 4
+        delay_warning_time = 4
 </pre>
 
 <p>
@@ -728,6 +741,45 @@ aliasing loops.
 
 <hr>
 
+<a name="numerical_log"><h3>Postfix logs SMTP clients as IP
+addresses</h3>
+
+<blockquote>
+
+The Postfix SMTP server logs client connections with numerical IP
+addresses instead of resolving the hostname. When I use <b>nslookup</b>
+the address does resolve to a name.
+
+</blockquote>
+
+<p>
+
+You run the Postfix SMTP server inside a <b>chroot</b> jail for
+extra security, but some configuration files are missing. In order
+to run inside a chroot jail, the Postfix SMTP client and server
+need copies of system configuration files inside the Postfix queue
+directory.  The exact list of files is very system dependent, but
+you will probably need at the very least:
+
+<p>
+
+<pre>
+    /var/spool/postfix/etc/resolv.conf
+    /var/spool/postfix/etc/services
+</pre>
+
+<p>
+
+Of course, these directories and files must be owned by root, but
+they must be accessible by the postfix user, so directories need
+mode 0755 and files need mode 0644.
+
+<p>
+For more details, see the files in the <b>examples/chroot-setup</b>
+directory of the Postfix source code distribution.
+
+<hr>
+
 <a name="open_relay"><h3>Help! Postfix is an open relay</h3>
 
 According to some relay checking software, Postfix accepts
@@ -838,8 +890,8 @@ ahead of the other SMTPD recipient restrictions:
 <pre>
     /etc/postfix/main.cf:
         smtpd_recipient_restrictions = 
-           regexp:/etc/postfix/regexp_access
-           ...other restrictions...
+            regexp:/etc/postfix/regexp_access
+            ...other restrictions...
 
     /etc/postfix/regexp_access:
         /[%!@].*[%!@]/ 550 Sender specified routing is not supported here.
@@ -1142,8 +1194,8 @@ that work around them.
 
 <pre>
     /etc/postfix/main.cf:
-       smtp_skip_4xx_greeting = yes
-       smtp_skip_5xx_greeting = yes
+        smtp_skip_4xx_greeting = yes
+        smtp_skip_5xx_greeting = yes
 </pre>
 
 <p>
@@ -1237,7 +1289,7 @@ in <b>/etc/postfix/master.cf</b>, specify:
 
 <pre>
     /etc/postfix/main.cf:
-       local_recipient_maps = $relocated_maps $alias_maps, unix:passwd.byname
+        local_recipient_maps = $relocated_maps $alias_maps, unix:passwd.byname
 </pre>
 
 <p>
@@ -1445,13 +1497,13 @@ expression-based filter at the SMTP port:
 
 <pre>
     /etc/postfix/main.cf:
-       smtpd_recipient_restrictions = 
-           ... regexp:/etc/postfix/access_regexp ...
-       smtpd_recipient_restrictions = 
-           ... pcre:/etc/postfix/access_regexp ...
+        smtpd_recipient_restrictions = 
+            ... regexp:/etc/postfix/access_regexp ...
+        smtpd_recipient_restrictions = 
+            ... pcre:/etc/postfix/access_regexp ...
 
     /etc/postfix/access_regexp:
-       /^(.*)-outgoing@(.*)/   554 Use $1@$2 instead
+        /^(.*)-outgoing@(.*)/   554 Use $1@$2 instead
 </pre>
 
 <p>
@@ -1515,6 +1567,50 @@ header</a>".
 
 <hr>
 
+<a name="worm"><h3>Postfix accepts MAIL FROM and RCPT TO "| command"</h3>
+
+With Postfix, | or / has special meaning only when it appears in
+aliases, .forward files or in :include: files. It has no special
+meaning in mail addresses.
+
+
+<p>
+
+If you must receive mail for systems with 10-year old vulnerabilities,
+it is prudent to set up a regexp filter that rejects potentially
+harmful MAIL FROM or RCPT TO commands.
+
+<p>
+
+<pre>
+    /etc/postfix/main.cf:
+        smtpd_sender_restrictions =
+            regexp:/etc/postfix/envelope-regexp
+            reject_unknown_sender_domain
+        smtpd_recipient_restrictions =
+            regexp:/etc/postfix/envelope-regexp
+            permit_mynetworks
+            check_relay_domains
+
+    /etc/postfix/envelope-regexp:
+        /[/|]/  REJECT
+</pre>
+
+<p>
+
+However, rejecting all envelope addresses with / causes trouble
+with simple-minded X.400 to Internet address mappings that leave
+the X.400 address structure exposed.
+
+<p>
+
+See also the documentation on <a href="uce.html#header_checks">header
+checks</a> restrictions for message header contents. These restrictions
+can be used to protect against attacks with command/file destinations
+in, for example, Errors-To: or Return-Receipt_To:  message headers.
+
+<hr>
+
 <a name="internal-list"><h3>Protecting internal email distribution lists</h3>
 
 <blockquote>
@@ -1766,14 +1862,14 @@ headers is sufficient to reliably implement a domain in a mailbox.
 
 <pre>
     /etc/postfix/main.cf:
-       recipient_delimiter = +
-       virtual_maps = 
-           ...non-regexp virtual maps...
-           regexp:/etc/postfix/virtual_regexp
+        recipient_delimiter = +
+        virtual_maps = 
+            ...non-regexp virtual maps...
+            regexp:/etc/postfix/virtual_regexp
 
     /etc/postfix/virtual_regexp:
-       /^virtual\.domain$/             whatever
-       /^(.*\)@virtual\.domain$/       joe+$1
+        /^virtual\.domain$/             whatever
+        /^(.*\)@virtual\.domain$/       joe+$1
 </pre>
 
 <p>
index bcbc2623dd5ccc57b1241a72306103af8a7a9be8..213a35b04f6f64281f755bbc9f39bd093d07d816 100644 (file)
@@ -289,40 +289,40 @@ QMGR(8)                                                   QMGR(8)
               list receive that same burst of  messages  a  whole
               day later.
 
+       <b>qmgr</b><i>_</i><b>site</b><i>_</i><b>hog</b><i>_</i><b>factor</b> (valid range: 10..100)
+              The  percentage  of  delivery resources that a busy
+              mail system will use up for delivery  to  a  single
+              site.   With  100%,  mail is delivered in first-in,
+              first-out order, so that a burst of  mail  for  one
+              site  can  block mail for other destinations.  With
+              less than 100%, the excess mail  is  deferred.  The
+              deferred  mail  is  delivered in little bursts, the
+              remainder of the backlog being deferred again, with
+              a lot of I/O activity happening as Postfix searches
+              the deferred queue for deliverable mail.
+
        <b>initial</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b>
-              Initial  per-destination concurrency level for par-
+              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
+              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-
+              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-
+              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
+              Limit  on  the  number  of  recipients  per message
               transfer, for the named message <i>transport</i>.
 
-<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
-       software.
-
-<b>AUTHOR(S)</b>
-       Wietse Venema
 
 
 
@@ -335,6 +335,18 @@ QMGR(8)                                                   QMGR(8)
 QMGR(8)                                                   QMGR(8)
 
 
+<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
+       software.
+
+<b>AUTHOR(S)</b>
+       Wietse Venema
        IBM T.J. Watson Research
        P.O. Box 704
        Yorktown Heights, NY 10598, USA
@@ -367,18 +379,6 @@ QMGR(8)                                                   QMGR(8)
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
 
 
 
index 4dfcdfd0e83e6c6d5de791b8ba6ee1d17323dcc7..5c6a4dd39ed06238b250f29d4d9bfce8f6b003cb 100644 (file)
@@ -122,9 +122,9 @@ SMTP(8)                                                   SMTP(8)
        <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
               Skip  servers that greet us with a 4xx status code.
 
-       <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b>
-              Do not wait for the server response  after  sending
-              QUIT.
+       <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>5xx</b><i>_</i><b>greeting</b>
+              Skip servers that greet us with a 5xx status  code.
+
 
 
 
@@ -137,38 +137,42 @@ SMTP(8)                                                   SMTP(8)
 SMTP(8)                                                   SMTP(8)
 
 
+       <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b>
+              Do  not  wait for the server response after sending
+              QUIT.
+
 <b>Resource</b> <b>controls</b>
        <b>smtp</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
               Limit the number of parallel deliveries to the same
-              destination.  The default limit is taken  from  the
+              destination.   The  default limit is taken from the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
 
        <b>smtp</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Limit  the  number of recipients per message deliv-
-              ery.   The  default  limit  is   taken   from   the
+              Limit the number of recipients per  message  deliv-
+              ery.    The   default   limit  is  taken  from  the
               <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
 
 <b>Timeout</b> <b>controls</b>
        <b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
               Timeout in seconds for completing a TCP connection.
               When no connection can be made within the deadline,
-              the  SMTP client tries the next address on the mail
+              the SMTP client tries the next address on the  mail
               exchanger list.
 
        <b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
-              Timeout in seconds for receiving the SMTP  greeting
+              Timeout  in seconds for receiving the SMTP greeting
               banner.  When the server drops the connection with-
-              out sending a greeting banner, or when it sends  no
+              out  sending a greeting banner, or when it sends no
               greeting  banner  within  the  deadline,  the  SMTP
               client tries the next address on the mail exchanger
               list.
 
        <b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
-              Timeout  in  seconds  for sending the <b>HELO</b> command,
+              Timeout in seconds for sending  the  <b>HELO</b>  command,
               and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>mail</b><i>_</i><b>timeout</b>
-              Timeout in seconds for sending the <b>MAIL</b>  <b>FROM</b>  com-
+              Timeout  in  seconds for sending the <b>MAIL</b> <b>FROM</b> com-
               mand, and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>rcpt</b><i>_</i><b>timeout</b>
@@ -176,7 +180,7 @@ SMTP(8)                                                   SMTP(8)
               and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>init</b><i>_</i><b>timeout</b>
-              Timeout in seconds for sending  the  <b>DATA</b>  command,
+              Timeout  in  seconds  for sending the <b>DATA</b> command,
               and for receiving the server response.
 
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
@@ -185,13 +189,9 @@ SMTP(8)                                                   SMTP(8)
        <b>smtp</b><i>_</i><b>data</b><i>_</i><b>done</b><i>_</i><b>timeout</b>
               Timeout in seconds for sending the "<b>.</b>" command, and
               for receiving the server response. When no response
-              is received, a warning is logged that the mail  may
+              is  received, a warning is logged that the mail may
               be delivered multiple times.
 
-       <b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
-              Timeout  in  seconds  for sending the <b>QUIT</b> command,
-              and for receiving the server response.
-
 
 
                                                                 3
@@ -203,6 +203,10 @@ SMTP(8)                                                   SMTP(8)
 SMTP(8)                                                   SMTP(8)
 
 
+       <b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
+              Timeout in seconds for sending  the  <b>QUIT</b>  command,
+              and for receiving the server response.
+
 <b>SEE</b> <b>ALSO</b>
        <a href="bounce.8.html">bounce(8)</a> non-delivery status reports
        <a href="master.8.html">master(8)</a> process manager
@@ -210,7 +214,7 @@ SMTP(8)                                                   SMTP(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
@@ -251,10 +255,6 @@ SMTP(8)                                                   SMTP(8)
 
 
 
-
-
-
-
 
 
 
index ec8eca5e91fb55f3e15cdf4324a9cbfdd7faf5e0..40fe847d5d3ea4110e623b1e0e187ba79124920e 100644 (file)
@@ -53,6 +53,7 @@
 #include <make_dirs.h>
 #include <set_eugid.h>
 #include <get_hostname.h>
+#include <sane_fsops.h>
 
 /* Global library. */
 
@@ -136,10 +137,10 @@ int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
        vstring_sprintf(why, "create %s: %m", tmpfile);
     } else {
        if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, why) == 0) {
-           if (link(tmpfile, newfile) < 0
+           if (sane_link(tmpfile, newfile) < 0
                && (errno != ENOENT
                    || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
-                   || link(tmpfile, newfile) < 0)) {
+                   || sane_link(tmpfile, newfile) < 0)) {
                vstring_sprintf(why, "link to %s: %m", newfile);
            } else {
                if (unlink(tmpfile) < 0)
index 1627dcb0b8d0af624fa2d96357dc84dbb8798e90..c92a1b216ce0cbde7d20ad326ed23675d02dd992 100644 (file)
@@ -58,15 +58,24 @@ case "$VERSION" in
 esac
 
 case "$SYSTEM.$RELEASE" in
+   SCO_SV.3.2) SYSTYPE=SCO5
+               # Use the native compiler by default
+               : ${CC="/usr/bin/cc -b elf"}
+               : ${DEBUG=}
+               SYSLIBS="-lsocket -ldbm"
+               RANLIB=echo
+               ;;
   UnixWare.5*) SYSTYPE=UW7
-               CC=cc
-               DEBUG=
+               # Use the native compiler by default
+               : ${CC=/usr/bin/cc}
+               : ${DEBUG=}
                RANLIB=echo
                SYSLIBS="-lresolv -lsocket -lnsl"
                ;;
   UNIX_SV.4.2*)        case "`uname -v`" in
              2.1*) SYSTYPE=UW21
-                   CC=/usr/bin/cc
+                   # Use the native compiler by default
+                   : ${CC=/usr/bin/cc}
                    RANLIB=echo
                    SYSLIBS="-lresolv -lsocket -lnsl -lc -L/usr/ucblib -lucb"
                    ;;
index c776af6da1e4c9b2c12ab04398f7965d10d82d86..08b328e098aa3e4bcc9a487a58f04923e28cb3d0 100644 (file)
@@ -8,7 +8,7 @@ COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
        man1/postsuper.1
 CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \
-       man5/transport.5 man5/virtual.5
+       man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5
 
 update:        $(DAEMONS) $(COMMANDS) $(CONFIG)
 
@@ -110,6 +110,12 @@ man5/aliases.5: ../conf/aliases
 man5/canonical.5: ../conf/canonical
        srctoman - $? >$@
 
+man5/pcre_table.5: ../conf/pcre_table
+       srctoman - $? >$@
+
+man5/regexp_table.5: ../conf/regexp_table
+       srctoman - $? >$@
+
 man5/relocated.5: ../conf/relocated
        srctoman - $? >$@
 
index f07281ae8ed222f5b669da5a479e0f8ca2c31cb5..f923d735348c31c96f9ee10b2ac659c4671ac8dd 100644 (file)
@@ -16,12 +16,23 @@ The optional \fBaccess\fR table directs the Postfix SMTP server
 to selectively reject or accept mail from or to specific hosts,
 domains, networks, host addresses or mail addresses.
 
-The table serves as input to the \fBpostmap\fR(1) command. The
-result, an indexed file in \fBdbm\fR or \fBdb\fR format,
+Normally, the table serves as input to the \fBpostmap\fR(1) command.
+The result, an indexed file in \fBdbm\fR or \fBdb\fR format,
 is used for fast searching by the mail system. After an update
 it may take a minute or so before the change becomes visible.
 Issue a \fBpostfix reload\fR command to eliminate the delay.
 
+When the table is provided via other means such as NIS, LDAP
+or SQL, the same lookups are done as for ordinary indexed files.
+
+Alternatively, the table can be provided as a regular-expression
+map where patterns are given as regular expressions. In that case,
+the lookups are done in a slightly different way as described below.
+.SH TABLE FORMAT
+.na
+.nf
+.ad
+.fi
 The format of the access table is as follows:
 .IP "blanks and comments"
 Blank lines are ignored, as are lines beginning with `#'.
@@ -31,9 +42,10 @@ perform the corresponding \fIaction\fR.
 .SH PATTERNS
 .na
 .nf
-Patterns are tried in the order as listed below:
 .ad
 .fi
+With lookups from indexed files, patterns are tried in the order as
+listed below:
 .IP \fIuser\fR@\fIdomain\fR
 Matches the specified mail address.
 .IP \fIdomain.name\fR
@@ -62,6 +74,29 @@ error response message is generated.
 .IP \fBOK\fR
 .IP "\fIAny other text\fR"
 Accept the address etc. that matches the pattern.
+.SH REGULAR EXPRESSION TABLES
+.na
+.nf
+.ad
+.fi
+This section describes how the table lookups change when the table
+is given in the form of regular expressions. For a description of
+regular expression lookup table syntax, see \fBregexp_table\fR(5)
+or \fBpcre_table\fR(5).
+
+Patterns become regular expressions that are applied to the entire
+string being looked up. Depending on the application, that string
+is an entire client hostname, an entire client IP address, or an
+entire mail address.
+
+In contrast to the normal lookups from indexed files, no parent
+domain or network search is done, and \fIuser@domain\fR mail
+addresses are not broken up into their \fIuser@\fR and \fIdomain\fR
+constituent parts.
+
+Actions are the same as with normal indexed file lookups, with
+the additional feature that parenthesized substrings from the
+pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on.
 .SH BUGS
 .ad
 .fi
@@ -71,6 +106,8 @@ The table format does not understand quoting conventions.
 .nf
 postmap(1) create mapping table
 smtpd(8) smtp server
+pcre_table(5) format of PCRE tables
+regexp_table(5) format of POSIX regexp tables
 .SH LICENSE
 .na
 .nf
index 444970acb988be0cb89f64382cc65fe9fdb19347..c0cb2ad961c9e380ee1410554d9596b53b98048d 100644 (file)
@@ -223,6 +223,15 @@ but large mailing list delivery performance suffers. In the worst
 case, recipients near the beginning of a large list receive a burst
 of messages immediately, while recipients near the end of that list
 receive that same burst of messages a whole day later.
+.IP "\fBqmgr_site_hog_factor\fR (valid range: 10..100)"
+The percentage of delivery resources that a busy mail system will
+use up for delivery to a single site.
+With 100%, mail is delivered in first-in, first-out order, so that
+a burst of mail for one site can block mail for other destinations.
+With less than 100%, the excess mail is deferred. The deferred mail
+is delivered in little bursts, the remainder of the backlog being
+deferred again, with a lot of I/O activity happening as Postfix
+searches the deferred queue for deliverable mail.
 .IP \fBinitial_destination_concurrency\fR
 Initial per-destination concurrency level for parallel delivery
 to the same destination.
index 18db2df16a2842e0c47435b3182c125e59b493b7..a4fc99e3ce0b5bf3eee6db77bad76ad3851385d8 100644 (file)
@@ -103,6 +103,8 @@ When this parameter includes the \fBprotocol\fR class, send mail to the
 postmaster with transcripts of SMTP sessions with protocol errors.
 .IP \fBsmtp_skip_4xx_greeting\fR
 Skip servers that greet us with a 4xx status code.
+.IP \fBsmtp_skip_5xx_greeting\fR
+Skip servers that greet us with a 5xx status code.
 .IP \fBsmtp_skip_quit_response\fR
 Do not wait for the server response after sending QUIT.
 .SH "Resource controls"
index edab09101c50b6a02ce592d31e22ec6e530f6244..0ad0fa7b16e070b3e3300b9bc26f379c8d313ce5 100644 (file)
@@ -159,7 +159,7 @@ void    master_sigsetup(void)
     char   *myname = "master_sigsetup";
     struct sigaction action;
     static int sigs[] = {
-       SIGINT, SIGQUIT, SIGSEGV, SIGILL, SIGTERM,
+       SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
     };
     unsigned i;
 
index fd9969748d0be9856d76818b04bb24de56413bf5..c612ab7d18150744fedda69f3ce894d9991ed328 100644 (file)
@@ -1,2 +1 @@
     "local_destination_concurrency_limit", "$default_destination_concurrency_limit", &var_local_destination_concurrency_limit, 0, 0,
-    "local_destination_recipient_limit", "$default_destination_recipient_limit", &var_local_destination_recipient_limit, 0, 0,
index aa4ee57e1b6fcd6338da268a4de1436308f1f750..c09dc14736c5ec4a9213076c6d1808aeb1463d2c 100644 (file)
@@ -1,2 +1 @@
 char   *var_local_destination_concurrency_limit;
-char   *var_local_destination_recipient_limit;
index 401c38600ea2220619a73e86a5266bf599f16453..3731ff8fa1ae6cec7a4afaec090ba2726379545b 100644 (file)
 /*     use up for delivery of a large mailing list message.
 /*     With 100%, delivery of one message does not begin before the previous
 /*     message has been delivered. This results in good performance for large
-/*     mailing lists, but results in poor response time for one-to-one mail. 
+/*     mailing lists, but results in poor response time for one-to-one mail.
 /*     With less than 100%, response time for one-to-one mail improves,
 /*     but large mailing list delivery performance suffers. In the worst
 /*     case, recipients near the beginning of a large list receive a burst
 /*     of messages immediately, while recipients near the end of that list
 /*     receive that same burst of messages a whole day later.
+/* .IP "\fBqmgr_site_hog_factor\fR (valid range: 10..100)"
+/*     The percentage of delivery resources that a busy mail system will
+/*     use up for delivery to a single site.
+/*     With 100%, mail is delivered in first-in, first-out order, so that
+/*     a burst of mail for one site can block mail for other destinations.
+/*     With less than 100%, the excess mail is deferred. The deferred mail
+/*     is delivered in little bursts, the remainder of the backlog being
+/*     deferred again, with a lot of I/O activity happening as Postfix
+/*     searches the deferred queue for deliverable mail.
 /* .IP \fBinitial_destination_concurrency\fR
 /*     Initial per-destination concurrency level for parallel delivery
 /*     to the same destination.
@@ -280,7 +289,9 @@ char   *var_relocated_maps;
 char   *var_virtual_maps;
 char   *var_defer_xports;
 bool    var_allow_min_user;
-bool    var_qmgr_fudge;
+int     var_qmgr_fudge;
+int     var_qmgr_hog;
+int     var_local_rcpt_lim;            /* XXX */
 
 static QMGR_SCAN *qmgr_incoming;
 static QMGR_SCAN *qmgr_deferred;
@@ -474,6 +485,8 @@ int     main(int argc, char **argv)
        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,
        VAR_QMGR_FUDGE, DEF_QMGR_FUDGE, &var_qmgr_fudge, 10, 100,
+       VAR_QMGR_HOG, DEF_QMGR_HOG, &var_qmgr_hog, 10, 100,
+       VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index 526566e30b9314d76ec7a8e686a093d498d229ef..c5c28a3000349287ea518640e41341ffcec06056 100644 (file)
@@ -528,8 +528,10 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         */
        if ((at = strrchr(STR(reply.recipient), '@')) == 0
            || resolve_local(at + 1)) {
+#if 0
            vstring_strcpy(reply.nexthop, STR(reply.recipient));
            (void) split_at_right(STR(reply.nexthop), '@');
+#endif
 #if 0
            if (*var_rcpt_delim)
                (void) split_addr(STR(reply.nexthop), *var_rcpt_delim);
@@ -541,7 +543,9 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
             * have to configure something for mail directed to the local
             * postmaster, though, but that is an RFC requirement anyway.
             */
-           if (strcasecmp(STR(reply.nexthop), var_double_bounce_sender) == 0) {
+           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);
@@ -611,6 +615,23 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
            continue;
        }
 
+       /*
+        * This queue is a hog. Defer this recipient until the queue drains.
+        * When a site accumulates a large backlog, Postfix will deliver a
+        * little chunk and hammer the disk as it defers the remainder of the
+        * backlog and searches the deferred queue for deliverable mail.
+        */
+       if (var_qmgr_hog < 100) {
+           if (queue->todo_refcount + queue->busy_refcount
+               > (var_qmgr_hog / 100.0)
+               * (qmgr_recipient_count > 0.8 * var_qmgr_rcpt_limit ?
+                  qmgr_message_count : var_qmgr_active_limit)) {
+               qmgr_defer_recipient(message, recipient->address,
+                                    "site destination queue overflow");
+               continue;
+           }
+       }
+
        /*
         * This queue is alive. Bind this recipient to this queue instance.
         */
index 2bf2c64b72d93852731cea4d9056acd16c7fbed0..04f5d4eb44383a220eef8203693664cc659f59e6 100644 (file)
@@ -134,6 +134,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 >= 500 && code < 510))
        state->error_mask |= MAIL_ERROR_PROTOCOL;
 }
index 17e7cdd9a24773411c7ce7ff894338c9ccdbeece..c511dde45ef6423f9c4fa6ee4ac59625b60897f5 100644 (file)
 /*     Restrict what domain names can be used in \fBETRN\fR commands,
 /*     and what clients may issue \fBETRN\fR commands.
 /* .IP \fBallow_untrusted_routing\fR
-/*     Allow untrusted clients to specify addresses with sender-specified 
-/*     routing.  Enabling this opens up nasty relay loopholes involving 
+/*     Allow untrusted clients to specify addresses with sender-specified
+/*     routing.  Enabling this opens up nasty relay loopholes involving
 /*     trusted backup MX hosts.
 /* .IP \fBrestriction_classes\fR
 /*     Declares the name of zero or more parameters that contain a
@@ -302,6 +302,7 @@ bool    var_disable_vrfy_cmd;
 char   *var_canonical_maps;
 char   *var_rcpt_canon_maps;
 char   *var_virtual_maps;
+char   *var_relocated_maps;
 char   *var_alias_maps;
 char   *var_local_rcpt_maps;
 bool    var_allow_untrust_route;
@@ -780,6 +781,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        rec_fprintf(state->cleanup, REC_TYPE_NORM,
                    "\tid %s; %s", state->queue_id, mail_date(state->time));
     }
+#ifdef RECEIVED_ENVELOPE_FROM
+    rec_fprintf(state->cleanup, REC_TYPE_NORM,
+               "\t(envelope-from %s)", state->sender);
+#endif
     smtpd_chat_reply(state, "354 End data with <CR><LF>.<CR><LF>");
 
     /*
@@ -1347,6 +1352,7 @@ int     main(int argc, char **argv)
        VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
        VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
        VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0,
+       VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
        VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
        VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
        0,
index 2c51019978f866861d0a7c8cab71641fa6cbd319..93a6ff4380b5a95a4bb01335ae3512f66f2e166a 100644 (file)
@@ -312,6 +312,7 @@ static MAPS *local_rcpt_maps;
 static MAPS *rcpt_canon_maps;
 static MAPS *canonical_maps;
 static MAPS *virtual_maps;
+static MAPS *relocated_maps;
 
  /*
   * Pre-opened access control lists.
@@ -455,6 +456,8 @@ void    smtpd_check_init(void)
                                 DICT_FLAG_LOCK);
     virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps,
                               DICT_FLAG_LOCK);
+    relocated_maps = maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
+                                DICT_FLAG_LOCK);
 
     /*
      * Reply is used as a cache for resolved addresses, and error_text is
@@ -1969,6 +1972,7 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
        if (*var_local_rcpt_maps
            && !mail_addr_find(rcpt_canon_maps, STR(reply.recipient), NOP)
            && !mail_addr_find(canonical_maps, STR(reply.recipient), NOP)
+           && !mail_addr_find(relocated_maps, STR(reply.recipient), NOP)
            && !mail_addr_find(local_rcpt_maps, STR(reply.recipient), NOP)) {
            (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
                                      "550 <%s>: User unknown", recipient);
@@ -1978,6 +1982,7 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
        if (*var_virtual_maps
            && !mail_addr_find(rcpt_canon_maps, STR(reply.recipient), NOP)
            && !mail_addr_find(canonical_maps, STR(reply.recipient), NOP)
+           && !mail_addr_find(relocated_maps, STR(reply.recipient), NOP)
            && !mail_addr_find(virtual_maps, STR(reply.recipient), NOP)
            && maps_find(virtual_maps, domain, 0)) {
            (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
@@ -2064,6 +2069,7 @@ char   *var_alias_maps;
 char   *var_rcpt_canon_maps;
 char   *var_canonical_maps;
 char   *var_virtual_maps;
+char   *var_relocated_maps;
 char   *var_local_rcpt_maps;
 
 typedef struct {
@@ -2081,6 +2087,7 @@ static STRING_TABLE string_table[] = {
     VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps,
     VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps,
     VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps,
+    VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps,
     VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps,
     0,
 };
index 7fe7b2e5bf358b7ac44ac52c44e146df434d7c3c..c1634b0aab8ff4df220542c7696908b3fc29c873 100644 (file)
@@ -20,7 +20,8 @@ SRCS  = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
        vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \
        write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
        stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \
-       clean_env.c watchdog.c spawn_command.c duplex_pipe.c
+       clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
+       sane_link.c
 OBJS   = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
        dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
@@ -42,7 +43,8 @@ OBJS  = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
        vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \
        write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
        stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \
-       clean_env.o watchdog.o spawn_command.o duplex_pipe.o
+       clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
+       sane_link.o
 HDRS   = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
        dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
@@ -57,7 +59,7 @@ HDRS  = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
        timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
        vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
        dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
-       watchdog.h spawn_command.h
+       watchdog.h spawn_command.h sane_fsops.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
        stream_test.c dup2_pass_on_exec.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
@@ -719,6 +721,14 @@ safe_open.o: safe_open.h
 sane_accept.o: sane_accept.c
 sane_accept.o: sys_defs.h
 sane_accept.o: sane_accept.h
+sane_link.o: sane_link.c
+sane_link.o: sys_defs.h
+sane_link.o: msg.h
+sane_link.o: sane_fsops.h
+sane_rename.o: sane_rename.c
+sane_rename.o: sys_defs.h
+sane_rename.o: msg.h
+sane_rename.o: sane_fsops.h
 scan_dir.o: scan_dir.c
 scan_dir.o: sys_defs.h
 scan_dir.o: msg.h
index ebf8fd019b963d3a4c7a793228aef4b989dcb155..5fe5e94577e616f801b27dfe42f8e19c666479ad 100644 (file)
@@ -72,9 +72,14 @@ int     make_dirs(const char *path, int perms)
        SKIP_WHILE(*cp != '/', cp);
        if ((saved_ch = *cp) != 0)
            *cp = 0;
-       if ((ret = stat(saved_path, &st)) < 0)
-           if (errno != ENOENT || (ret = mkdir(saved_path, perms)) < 0)
+       if ((ret = stat(saved_path, &st)) >= 0) {
+           if (!S_ISDIR(st.st_mode)) {
+               errno = ENOTDIR;
+               ret = -1;
                break;
+           }
+       } else if (errno != ENOENT || (ret = mkdir(saved_path, perms)) < 0)
+           break;
        if (saved_ch != 0)
            *cp = saved_ch;
        SKIP_WHILE(*cp == '/', cp);
index fae3e5341b62a500d6aef19473312e0fdf747d75..07dce44e3149fbf4a355319f032898ae3b09da5f 100644 (file)
 /*     <2rdb0s$568@mail.fwi.uva.nl>, posted to comp.security.unix
 /*     (May 18, 1994).
 /*
-/*     Olaf Kirch discusses how the lstat()/open()+stat() test can
+/*     Olaf Kirch discusses how the lstat()/open()+fstat() test can
 /*     be fooled by delaying the open() until the inode found with
 /*     lstat() has been re-used for a sensitive file (article
 /*     <20000103212443.A5807@monad.swb.de> posted to bugtraq on
-/*     Jan 3, 2000).  This can be a concern for set-uid processes
-/*     that run under the control of a user and this can be
+/*     Jan 3, 2000).  This can be a concern for a set-uid process
+/*     that runs under the control of a user and that can be
 /*     manipulated with start/stop signals.
 /* LICENSE
 /* .ad
diff --git a/postfix/util/sane_fsops.h b/postfix/util/sane_fsops.h
new file mode 100644 (file)
index 0000000..0c9b3ac
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _SANE_FSOPS_H_
+#define _SANE_FSOPS_H_
+
+/*++
+/* NAME
+/*     sane_rename 3h
+/* SUMMARY
+/*     sanitize rename() error returns
+/* SYNOPSIS
+/*     #include <sane_rename.h>
+/* DESCRIPTION
+/* .nf
+
+ /* External interface. */
+
+extern int sane_rename(const char *, const char *);
+extern int sane_link(const char *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/util/sane_link.c b/postfix/util/sane_link.c
new file mode 100644 (file)
index 0000000..13c071c
--- /dev/null
@@ -0,0 +1,71 @@
+/*++
+/* NAME
+/*     sane_link 3
+/* SUMMARY
+/*     sanitize link() error returns
+/* SYNOPSIS
+/*     #include <sane_fsops.h>
+/*
+/*     int     sane_link(old, new)
+/*     const char *from;
+/*     const char *to;
+/* DESCRIPTION
+/*     sane_link() implements the link(2) system call, and works
+/*     around some errors that are possible with NFS file systems.
+/* 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 <errno.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include "msg.h"
+#include "sane_fsops.h"
+
+/* sane_link - sanitize link() error returns */
+
+int     sane_link(const char *from, const char *to)
+{
+    char   *myname = "sane_link";
+    int     saved_errno;
+    struct stat from_st;
+    struct stat to_st;
+
+    /*
+     * Normal case: link() succeeds.
+     */
+    if (link(from, to) >= 0)
+       return (0);
+
+    /*
+     * Woops. Save errno, and see if the error is an NFS artefact. If it is,
+     * pretend the error never happened.
+     */
+    saved_errno = errno;
+    if (stat(from, &from_st) >= 0 && stat(to, &to_st) >= 0
+       && from_st.st_dev == to_st.st_dev
+       && from_st.st_ino == to_st.st_ino) {
+       msg_info("%s(%s,%s): worked around spurious NFS error",
+                myname, from, to);
+       return (0);
+    }
+
+    /*
+     * Nope, it didn't. Restore errno and report the error.
+     */
+    errno = saved_errno;
+    return (-1);
+}
diff --git a/postfix/util/sane_rename.c b/postfix/util/sane_rename.c
new file mode 100644 (file)
index 0000000..416f897
--- /dev/null
@@ -0,0 +1,68 @@
+/*++
+/* NAME
+/*     sane_rename 3
+/* SUMMARY
+/*     sanitize rename() error returns
+/* SYNOPSIS
+/*     #include <sane_fsops.h>
+/*
+/*     int     sane_rename(old, new)
+/*     const char *from;
+/*     const char *to;
+/* DESCRIPTION
+/*     sane_rename() implements the rename(2) system call, and works
+/*     around some errors that are possible with NFS file systems.
+/* 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 <errno.h>
+#include <stdio.h>                     /* rename(2) syscall in stdio.h? */
+
+/* Utility library. */
+
+#include "msg.h"
+#include "sane_fsops.h"
+
+/* sane_rename - sanitize rename() error returns */
+
+int     sane_rename(const char *from, const char *to)
+{
+    char   *myname = "sane_rename";
+    int     saved_errno;
+    struct stat st;
+
+    /*
+     * Normal case: rename() succeeds.
+     */
+    if (rename(from, to) >= 0)
+       return (0);
+
+    /*
+     * Woops. Save errno, and see if the error is an NFS artefact. If it is,
+     * pretend the error never happened.
+     */
+    saved_errno = errno;
+    if (stat(from, &st) < 0 && stat(to, &st) >= 0) {
+       msg_info("%s(%s,%s): worked around spurious NFS error",
+                myname, from, to);
+       return (0);
+    }
+
+    /*
+     * Nope, it didn't. Restore errno and report the error.
+     */
+    errno = saved_errno;
+    return (-1);
+}
index 9ad93b8704113c278b941a608cdef6581631a849..a0a18b44e657a1ccc413c4483d81c9e2847f46e9 100644 (file)
@@ -79,7 +79,6 @@
 #define FD_SETSIZE     96
 #endif
 #include <sys/types.h>
-#define UNSAFE_CTYPE                   /* XXX verify */
 #define _PATH_MAILDIR  "/var/spool/mail"
 #define _PATH_BSHELL   "/bin/sh"
 #define _PATH_DEFPATH  "/bin:/usr/bin:/usr/ucb"
@@ -603,6 +602,37 @@ extern int opterr;                 /* XXX use <getopt.h> */
 #ifndef S_ISSOCK
 #define S_ISSOCK(mode) ((mode&0xF000) == 0xC000)
 #endif
+#endif
+
+#ifdef SCO5
+#define SUPPORTED
+#include <sys/types.h>
+#include <sys/socket.h>
+extern int h_errno;
+
+#define _PATH_MAILDIR  "/usr/spool/mail"
+#define _PATH_BSHELL   "/bin/sh"
+#define _PATH_DEFPATH  "/bin:/usr/bin"
+#define USE_PATHS_H
+#define USE_FCNTL_LOCK
+#define USE_DOT_LOCK
+#define HAS_FSYNC
+#define HAS_DBM
+#define DEF_DB_TYPE    "dbm"
+#define ALIAS_DB_MAP   "dbm:/etc/mail/aliases"
+#define DBM_NO_TRAILING_NULL
+#define HAS_NIS
+#define GETTIMEOFDAY(t)        gettimeofday(t,(struct timezone *) 0)
+#define ROOT_PATH      "/bin:/etc:/usr/bin:/tcb/bin"
+#define USE_STATVFS
+#define STATVFS_IN_SYS_STATVFS_H
+#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
+#define MISSING_SETENV
+/* SCO5 misses just S_ISSOCK, the others are there
+ * Use C_ISSOCK definition from cpio.h.
+ */
+#include <cpio.h>
+#define S_ISSOCK(mode) (((mode) & (S_IFMT)) == (C_ISSOCK))
 #endif
 
  /*