summaryrefslogtreecommitdiffstats
path: root/src/cleanup/cleanup.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cleanup/cleanup.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/src/cleanup/cleanup.c b/src/cleanup/cleanup.c
new file mode 100644
index 0000000..6fe61f8
--- /dev/null
+++ b/src/cleanup/cleanup.c
@@ -0,0 +1,656 @@
+/*++
+/* NAME
+/* cleanup 8
+/* SUMMARY
+/* canonicalize and enqueue Postfix message
+/* SYNOPSIS
+/* \fBcleanup\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/* The \fBcleanup\fR(8) daemon processes inbound mail, inserts it
+/* into the \fBincoming\fR mail queue, and informs the queue
+/* manager of its arrival.
+/*
+/* The \fBcleanup\fR(8) daemon performs the following transformations:
+/* .IP \(bu
+/* Insert missing message headers: (\fBResent-\fR) \fBFrom:\fR,
+/* \fBTo:\fR, \fBMessage-Id:\fR, and \fBDate:\fR.
+/* .br
+/* This is enabled with the \fBlocal_header_rewrite_clients\fR and
+/* \fBalways_add_missing_headers\fR parameter settings.
+/* .IP \(bu
+/* Transform envelope and header addresses to the standard
+/* \fIuser@fully-qualified-domain\fR form that is expected by other
+/* Postfix programs.
+/* This task depends on the \fBtrivial-rewrite\fR(8) daemon.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
+/* .IP \(bu
+/* Eliminate duplicate envelope recipient addresses.
+/* .br
+/* This is enabled with the \fBduplicate_filter_limit\fR
+/* parameter setting.
+/* .IP \(bu
+/* Remove message headers: \fBBcc\fR, \fBContent-Length\fR,
+/* \fBResent-Bcc\fR, \fBReturn-Path\fR.
+/* .br
+/* This is enabled with the message_drop_headers parameter
+/* setting.
+/* .IP \(bu
+/* Optionally, rewrite all envelope and header addresses according
+/* to the mappings specified in the \fBcanonical\fR(5) lookup tables.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
+/* .IP \(bu
+/* Optionally, masquerade envelope sender addresses and message
+/* header addresses (i.e. strip host or domain information below
+/* all domains listed in the \fBmasquerade_domains\fR parameter,
+/* except for user names listed in \fBmasquerade_exceptions\fR).
+/* By default, address masquerading does not affect envelope recipients.
+/* .br
+/* The header transformation is enabled with the
+/* \fBlocal_header_rewrite_clients\fR parameter setting.
+/* .IP \(bu
+/* Optionally, expand envelope recipients according to information
+/* found in the \fBvirtual_alias_maps\fR lookup tables.
+/* .PP
+/* The \fBcleanup\fR(8) daemon performs sanity checks on the content of
+/* each message. When it finds a problem, by default it returns a
+/* diagnostic status to the cleanup service client, and leaves
+/* it up to the client
+/* to deal with the problem. Alternatively, the client can request
+/* the \fBcleanup\fR(8) daemon to bounce the message back to the sender
+/* in case of trouble.
+/* STANDARDS
+/* RFC 822 (ARPA Internet Text Messages)
+/* RFC 2045 (MIME: Format of Internet Message Bodies)
+/* RFC 2046 (MIME: Media Types)
+/* RFC 2822 (Internet Message Format)
+/* RFC 3463 (Enhanced Status Codes)
+/* RFC 3464 (Delivery status notifications)
+/* RFC 5322 (Internet Message Format)
+/* DIAGNOSTICS
+/* Problems and transactions are logged to \fBsyslogd\fR(8)
+/* or \fBpostlogd\fR(8).
+/* BUGS
+/* Table-driven rewriting rules make it hard to express \fBif then
+/* else\fR and other logical relationships.
+/* CONFIGURATION PARAMETERS
+/* .ad
+/* .fi
+/* Changes to \fBmain.cf\fR are picked up automatically, as
+/* \fBcleanup\fR(8)
+/* processes run for only a limited amount of time. Use the command
+/* "\fBpostfix reload\fR" to speed up a change.
+/*
+/* The text below provides only a parameter summary. See
+/* \fBpostconf\fR(5) for more details including examples.
+/* COMPATIBILITY CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBundisclosed_recipients_header (see 'postconf -d' output)\fR"
+/* Message header that the Postfix \fBcleanup\fR(8) server inserts when a
+/* message contains no To: or Cc: message header.
+/* .PP
+/* Available in Postfix version 2.1 only:
+/* .IP "\fBenable_errors_to (no)\fR"
+/* Report mail delivery errors to the address specified with the
+/* non-standard Errors-To: message header, instead of the envelope
+/* sender address (this feature is removed with Postfix version 2.2, is
+/* turned off by default with Postfix version 2.1, and is always turned on
+/* with older Postfix versions).
+/* .PP
+/* Available in Postfix version 2.6 and later:
+/* .IP "\fBalways_add_missing_headers (no)\fR"
+/* Always add (Resent-) From:, To:, Date: or Message-ID: headers
+/* when not present.
+/* .PP
+/* Available in Postfix version 2.9 and later:
+/* .IP "\fBenable_long_queue_ids (no)\fR"
+/* Enable long, non-repeating, queue IDs (queue file names).
+/* .PP
+/* Available in Postfix version 3.0 and later:
+/* .IP "\fBmessage_drop_headers (bcc, content-length, resent-bcc, return-path)\fR"
+/* Names of message headers that the \fBcleanup\fR(8) daemon will remove
+/* after applying \fBheader_checks\fR(5) and before invoking Milter applications.
+/* .IP "\fBheader_from_format (standard)\fR"
+/* The format of the Postfix-generated \fBFrom:\fR header.
+/* BUILT-IN CONTENT FILTERING CONTROLS
+/* .ad
+/* .fi
+/* Postfix built-in content filtering is meant to stop a flood of
+/* worms or viruses. It is not a general content filter.
+/* .IP "\fBbody_checks (empty)\fR"
+/* Optional lookup tables for content inspection as specified in
+/* the \fBbody_checks\fR(5) manual page.
+/* .IP "\fBheader_checks (empty)\fR"
+/* Optional lookup tables for content inspection of primary non-MIME
+/* message headers, as specified in the \fBheader_checks\fR(5) manual page.
+/* .PP
+/* Available in Postfix version 2.0 and later:
+/* .IP "\fBbody_checks_size_limit (51200)\fR"
+/* How much text in a message body segment (or attachment, if you
+/* prefer to use that term) is subjected to body_checks inspection.
+/* .IP "\fBmime_header_checks ($header_checks)\fR"
+/* Optional lookup tables for content inspection of MIME related
+/* message headers, as described in the \fBheader_checks\fR(5) manual page.
+/* .IP "\fBnested_header_checks ($header_checks)\fR"
+/* Optional lookup tables for content inspection of non-MIME message
+/* headers in attached messages, as described in the \fBheader_checks\fR(5)
+/* manual page.
+/* .PP
+/* Available in Postfix version 2.3 and later:
+/* .IP "\fBmessage_reject_characters (empty)\fR"
+/* The set of characters that Postfix will reject in message
+/* content.
+/* .IP "\fBmessage_strip_characters (empty)\fR"
+/* The set of characters that Postfix will remove from message
+/* content.
+/* .PP
+/* Available in Postfix version 3.9, 3.8.5, 3.7.10, 3.6.14,
+/* 3.5.24, and later:
+/* .IP "\fBcleanup_replace_stray_cr_lf (yes)\fR"
+/* Replace each stray <CR> or <LF> character in message
+/* content with a space character, to prevent outbound SMTP smuggling,
+/* and to make the evaluation of Postfix-added DKIM or other signatures
+/* independent from how a remote mail server handles such characters.
+/* BEFORE QUEUE MILTER CONTROLS
+/* .ad
+/* .fi
+/* As of version 2.3, Postfix supports the Sendmail version 8
+/* Milter (mail filter) protocol. When mail is not received via
+/* the smtpd(8) server, the cleanup(8) server will simulate
+/* SMTP events to the extent that this is possible. For details
+/* see the MILTER_README document.
+/* .IP "\fBnon_smtpd_milters (empty)\fR"
+/* A list of Milter (mail filter) applications for new mail that
+/* does not arrive via the Postfix \fBsmtpd\fR(8) server.
+/* .IP "\fBmilter_protocol (6)\fR"
+/* The mail filter protocol version and optional protocol extensions
+/* for communication with a Milter application; prior to Postfix 2.6
+/* the default protocol is 2.
+/* .IP "\fBmilter_default_action (tempfail)\fR"
+/* The default action when a Milter (mail filter) response is
+/* unavailable (for example, bad Postfix configuration or Milter
+/* failure).
+/* .IP "\fBmilter_macro_daemon_name ($myhostname)\fR"
+/* The {daemon_name} macro value for Milter (mail filter) applications.
+/* .IP "\fBmilter_macro_v ($mail_name $mail_version)\fR"
+/* The {v} macro value for Milter (mail filter) applications.
+/* .IP "\fBmilter_connect_timeout (30s)\fR"
+/* The time limit for connecting to a Milter (mail filter)
+/* application, and for negotiating protocol options.
+/* .IP "\fBmilter_command_timeout (30s)\fR"
+/* The time limit for sending an SMTP command to a Milter (mail
+/* filter) application, and for receiving the response.
+/* .IP "\fBmilter_content_timeout (300s)\fR"
+/* The time limit for sending message content to a Milter (mail
+/* filter) application, and for receiving the response.
+/* .IP "\fBmilter_connect_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after completion of an SMTP connection.
+/* .IP "\fBmilter_helo_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after the SMTP HELO or EHLO command.
+/* .IP "\fBmilter_mail_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after the SMTP MAIL FROM command.
+/* .IP "\fBmilter_rcpt_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after the SMTP RCPT TO command.
+/* .IP "\fBmilter_data_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to version 4 or higher Milter (mail
+/* filter) applications after the SMTP DATA command.
+/* .IP "\fBmilter_unknown_command_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to version 3 or higher Milter (mail
+/* filter) applications after an unknown SMTP command.
+/* .IP "\fBmilter_end_of_data_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after the message end-of-data.
+/* .PP
+/* Available in Postfix version 2.5 and later:
+/* .IP "\fBmilter_end_of_header_macros (see 'postconf -d' output)\fR"
+/* The macros that are sent to Milter (mail filter) applications
+/* after the end of the message header.
+/* .PP
+/* Available in Postfix version 2.7 and later:
+/* .IP "\fBmilter_header_checks (empty)\fR"
+/* Optional lookup tables for content inspection of message headers
+/* that are produced by Milter applications.
+/* .PP
+/* Available in Postfix version 3.1 and later:
+/* .IP "\fBmilter_macro_defaults (empty)\fR"
+/* Optional list of \fIname=value\fR pairs that specify default
+/* values for arbitrary macros that Postfix may send to Milter
+/* applications.
+/* MIME PROCESSING CONTROLS
+/* .ad
+/* .fi
+/* Available in Postfix version 2.0 and later:
+/* .IP "\fBdisable_mime_input_processing (no)\fR"
+/* Turn off MIME processing while receiving mail.
+/* .IP "\fBmime_boundary_length_limit (2048)\fR"
+/* The maximal length of MIME multipart boundary strings.
+/* .IP "\fBmime_nesting_limit (100)\fR"
+/* The maximal recursion level that the MIME processor will handle.
+/* .IP "\fBstrict_8bitmime (no)\fR"
+/* Enable both strict_7bit_headers and strict_8bitmime_body.
+/* .IP "\fBstrict_7bit_headers (no)\fR"
+/* Reject mail with 8-bit text in message headers.
+/* .IP "\fBstrict_8bitmime_body (no)\fR"
+/* Reject 8-bit message body text without 8-bit MIME content encoding
+/* information.
+/* .IP "\fBstrict_mime_encoding_domain (no)\fR"
+/* Reject mail with invalid Content-Transfer-Encoding: information
+/* for the message/* or multipart/* MIME content types.
+/* .PP
+/* Available in Postfix version 2.5 and later:
+/* .IP "\fBdetect_8bit_encoding_header (yes)\fR"
+/* Automatically detect 8BITMIME body content by looking at
+/* Content-Transfer-Encoding: message headers; historically, this
+/* behavior was hard-coded to be "always on".
+/* AUTOMATIC BCC RECIPIENT CONTROLS
+/* .ad
+/* .fi
+/* Postfix can automatically add BCC (blind carbon copy)
+/* when mail enters the mail system:
+/* .IP "\fBalways_bcc (empty)\fR"
+/* Optional address that receives a "blind carbon copy" of each message
+/* that is received by the Postfix mail system.
+/* .PP
+/* Available in Postfix version 2.1 and later:
+/* .IP "\fBsender_bcc_maps (empty)\fR"
+/* Optional BCC (blind carbon-copy) address lookup tables, indexed
+/* by sender address.
+/* .IP "\fBrecipient_bcc_maps (empty)\fR"
+/* Optional BCC (blind carbon-copy) address lookup tables, indexed by
+/* recipient address.
+/* ADDRESS TRANSFORMATION CONTROLS
+/* .ad
+/* .fi
+/* Address rewriting is delegated to the \fBtrivial-rewrite\fR(8) daemon.
+/* The \fBcleanup\fR(8) server implements table driven address mapping.
+/* .IP "\fBempty_address_recipient (MAILER-DAEMON)\fR"
+/* The recipient of mail addressed to the null address.
+/* .IP "\fBcanonical_maps (empty)\fR"
+/* Optional address mapping lookup tables for message headers and
+/* envelopes.
+/* .IP "\fBrecipient_canonical_maps (empty)\fR"
+/* Optional address mapping lookup tables for envelope and header
+/* recipient addresses.
+/* .IP "\fBsender_canonical_maps (empty)\fR"
+/* Optional address mapping lookup tables for envelope and header
+/* sender addresses.
+/* .IP "\fBmasquerade_classes (envelope_sender, header_sender, header_recipient)\fR"
+/* What addresses are subject to address masquerading.
+/* .IP "\fBmasquerade_domains (empty)\fR"
+/* Optional list of domains whose subdomain structure will be stripped
+/* off in email addresses.
+/* .IP "\fBmasquerade_exceptions (empty)\fR"
+/* Optional list of user names that are not subjected to address
+/* masquerading, even when their addresses match $masquerade_domains.
+/* .IP "\fBpropagate_unmatched_extensions (canonical, virtual)\fR"
+/* What address lookup tables copy an address extension from the lookup
+/* key to the lookup result.
+/* .PP
+/* Available before Postfix version 2.0:
+/* .IP "\fBvirtual_maps (empty)\fR"
+/* Optional lookup tables with a) names of domains for which all
+/* addresses are aliased to addresses in other local or remote domains,
+/* and b) addresses that are aliased to addresses in other local or
+/* remote domains.
+/* .PP
+/* Available in Postfix version 2.0 and later:
+/* .IP "\fBvirtual_alias_maps ($virtual_maps)\fR"
+/* Optional lookup tables that alias specific mail addresses or domains
+/* to other local or remote address.
+/* .PP
+/* Available in Postfix version 2.2 and later:
+/* .IP "\fBcanonical_classes (envelope_sender, envelope_recipient, header_sender, header_recipient)\fR"
+/* What addresses are subject to canonical_maps address mapping.
+/* .IP "\fBrecipient_canonical_classes (envelope_recipient, header_recipient)\fR"
+/* What addresses are subject to recipient_canonical_maps address
+/* mapping.
+/* .IP "\fBsender_canonical_classes (envelope_sender, header_sender)\fR"
+/* What addresses are subject to sender_canonical_maps address
+/* mapping.
+/* .IP "\fBremote_header_rewrite_domain (empty)\fR"
+/* Don't rewrite message headers from remote clients at all when
+/* this parameter is empty; otherwise, rewrite message headers and
+/* append the specified domain name to incomplete addresses.
+/* RESOURCE AND RATE CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBduplicate_filter_limit (1000)\fR"
+/* The maximal number of addresses remembered by the address
+/* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or
+/* for \fBshowq\fR(8) queue displays.
+/* .IP "\fBheader_size_limit (102400)\fR"
+/* The maximal amount of memory in bytes for storing a message header.
+/* .IP "\fBhopcount_limit (50)\fR"
+/* The maximal number of Received: message headers that is allowed
+/* in the primary message headers.
+/* .IP "\fBin_flow_delay (1s)\fR"
+/* Time to pause before accepting a new message, when the message
+/* arrival rate exceeds the message delivery rate.
+/* .IP "\fBmessage_size_limit (10240000)\fR"
+/* The maximal size in bytes of a message, including envelope information.
+/* .PP
+/* Available in Postfix version 2.0 and later:
+/* .IP "\fBheader_address_token_limit (10240)\fR"
+/* The maximal number of address tokens are allowed in an address
+/* message header.
+/* .IP "\fBmime_boundary_length_limit (2048)\fR"
+/* The maximal length of MIME multipart boundary strings.
+/* .IP "\fBmime_nesting_limit (100)\fR"
+/* The maximal recursion level that the MIME processor will handle.
+/* .IP "\fBqueue_file_attribute_count_limit (100)\fR"
+/* The maximal number of (name=value) attributes that may be stored
+/* in a Postfix queue file.
+/* .PP
+/* Available in Postfix version 2.1 and later:
+/* .IP "\fBvirtual_alias_expansion_limit (1000)\fR"
+/* The maximal number of addresses that virtual alias expansion produces
+/* from each original recipient.
+/* .IP "\fBvirtual_alias_recursion_limit (1000)\fR"
+/* The maximal nesting depth of virtual alias expansion.
+/* .PP
+/* Available in Postfix version 3.0 and later:
+/* .IP "\fBvirtual_alias_address_length_limit (1000)\fR"
+/* The maximal length of an email address after virtual alias expansion.
+/* SMTPUTF8 CONTROLS
+/* .ad
+/* .fi
+/* Preliminary SMTPUTF8 support is introduced with Postfix 3.0.
+/* .IP "\fBsmtputf8_enable (yes)\fR"
+/* Enable preliminary SMTPUTF8 support for the protocols described
+/* in RFC 6531..6533.
+/* .IP "\fBsmtputf8_autodetect_classes (sendmail, verify)\fR"
+/* Detect that a message requires SMTPUTF8 support for the specified
+/* mail origin classes.
+/* .PP
+/* Available in Postfix version 3.2 and later:
+/* .IP "\fBenable_idna2003_compatibility (no)\fR"
+/* Enable 'transitional' compatibility between IDNA2003 and IDNA2008,
+/* when converting UTF-8 domain names to/from the ASCII form that is
+/* used for DNS lookups.
+/* MISCELLANEOUS CONTROLS
+/* .ad
+/* .fi
+/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
+/* The default location of the Postfix main.cf and master.cf
+/* configuration files.
+/* .IP "\fBdaemon_timeout (18000s)\fR"
+/* How much time a Postfix daemon process may take to handle a
+/* request before it is terminated by a built-in watchdog timer.
+/* .IP "\fBdelay_logging_resolution_limit (2)\fR"
+/* The maximal number of digits after the decimal point when logging
+/* sub-second delay values.
+/* .IP "\fBdelay_warning_time (0h)\fR"
+/* The time after which the sender receives a copy of the message
+/* headers of mail that is still queued.
+/* .IP "\fBipc_timeout (3600s)\fR"
+/* The time limit for sending or receiving information over an internal
+/* communication channel.
+/* .IP "\fBmax_idle (100s)\fR"
+/* The maximum amount of time that an idle Postfix daemon process waits
+/* for an incoming connection before terminating voluntarily.
+/* .IP "\fBmax_use (100)\fR"
+/* The maximal number of incoming connections that a Postfix daemon
+/* process will service before terminating voluntarily.
+/* .IP "\fBmyhostname (see 'postconf -d' output)\fR"
+/* The internet hostname of this mail system.
+/* .IP "\fBmyorigin ($myhostname)\fR"
+/* The domain name that locally-posted mail appears to come
+/* from, and that locally posted mail is delivered to.
+/* .IP "\fBprocess_id (read-only)\fR"
+/* The process ID of a Postfix command or daemon process.
+/* .IP "\fBprocess_name (read-only)\fR"
+/* The process name of a Postfix command or daemon process.
+/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
+/* The location of the Postfix top-level queue directory.
+/* .IP "\fBsoft_bounce (no)\fR"
+/* Safety net to keep mail queued that would otherwise be returned to
+/* the sender.
+/* .IP "\fBsyslog_facility (mail)\fR"
+/* The syslog facility of Postfix logging.
+/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
+/* A prefix that is prepended to the process name in syslog
+/* records, so that, for example, "smtpd" becomes "prefix/smtpd".
+/* .PP
+/* Available in Postfix version 2.1 and later:
+/* .IP "\fBenable_original_recipient (yes)\fR"
+/* Enable support for the original recipient address after an
+/* address is rewritten to a different address (for example with
+/* aliasing or with canonical mapping).
+/* .PP
+/* Available in Postfix 3.3 and later:
+/* .IP "\fBservice_name (read-only)\fR"
+/* The master.cf service name of a Postfix daemon process.
+/* .PP
+/* Available in Postfix 3.5 and later:
+/* .IP "\fBinfo_log_address_format (external)\fR"
+/* The email address form that will be used in non-debug logging
+/* (info, warning, etc.).
+/* FILES
+/* /etc/postfix/canonical*, canonical mapping table
+/* /etc/postfix/virtual*, virtual mapping table
+/* SEE ALSO
+/* trivial-rewrite(8), address rewriting
+/* qmgr(8), queue manager
+/* header_checks(5), message header content inspection
+/* body_checks(5), body parts content inspection
+/* canonical(5), canonical address lookup table format
+/* virtual(5), virtual alias lookup table format
+/* postconf(5), configuration parameters
+/* master(5), generic daemon options
+/* master(8), process manager
+/* postlogd(8), Postfix logging
+/* syslogd(8), system logging
+/* README FILES
+/* .ad
+/* .fi
+/* Use "\fBpostconf readme_directory\fR" or
+/* "\fBpostconf html_directory\fR" to locate this information.
+/* .na
+/* .nf
+/* ADDRESS_REWRITING_README Postfix address manipulation
+/* CONTENT_INSPECTION_README content inspection
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <dict.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <cleanup_user.h>
+#include <mail_proto.h>
+#include <mail_params.h>
+#include <record.h>
+#include <rec_type.h>
+#include <mail_version.h>
+
+/* Single-threaded server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+#include "cleanup.h"
+
+/* cleanup_service - process one request to inject a message into the queue */
+
+static void cleanup_service(VSTREAM *src, char *unused_service, char **argv)
+{
+ VSTRING *buf = vstring_alloc(100);
+ CLEANUP_STATE *state;
+ int flags;
+ int type = 0;
+ int status;
+
+ /*
+ * Sanity check. This service takes no command-line arguments.
+ */
+ if (argv[0])
+ msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+ /*
+ * Open a queue file and initialize state.
+ */
+ state = cleanup_open(src);
+
+ /*
+ * 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.
+ */
+ attr_print(src, ATTR_FLAG_NONE,
+ SEND_ATTR_STR(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_CLEANUP),
+ SEND_ATTR_STR(MAIL_ATTR_QUEUEID, state->queue_id),
+ ATTR_TYPE_END);
+ if (attr_scan(src, ATTR_FLAG_STRICT,
+ RECV_ATTR_INT(MAIL_ATTR_FLAGS, &flags),
+ ATTR_TYPE_END) != 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.
+ */
+ while (CLEANUP_OUT_OK(state)) {
+ if ((type = rec_get_raw(src, buf, 0, REC_FLAG_NONE)) < 0) {
+ state->errs |= CLEANUP_STAT_BAD;
+ break;
+ }
+ if (REC_GET_HIDDEN_TYPE(type)) {
+ msg_warn("%s: record type %d not allowed - discarding this message",
+ state->queue_id, type);
+ state->errs |= CLEANUP_STAT_BAD;
+ break;
+ }
+ CLEANUP_RECORD(state, type, vstring_str(buf), VSTRING_LEN(buf));
+ if (type == REC_TYPE_END)
+ break;
+ }
+
+ /*
+ * Keep reading in case of problems, until the sender is ready to receive
+ * our status report.
+ */
+ if (CLEANUP_OUT_OK(state) == 0 && type > 0) {
+ while (type != REC_TYPE_END
+ && (type = rec_get_raw(src, buf, 0, REC_FLAG_NONE)) > 0) {
+ if (type == REC_TYPE_MILT_COUNT) {
+ int milter_count = atoi(vstring_str(buf));
+
+ /* Avoid deadlock. */
+ if (milter_count >= 0)
+ cleanup_milter_receive(state, milter_count);
+ }
+ }
+ }
+
+ /*
+ * Log something to make timeout errors easier to debug.
+ */
+ if (vstream_ftimeout(src))
+ msg_warn("%s: read timeout on %s",
+ state->queue_id, VSTREAM_PATH(src));
+
+ /*
+ * Finish this message, and report the result status to the client.
+ */
+ status = cleanup_flush(state); /* in case state is modified */
+ attr_print(src, ATTR_FLAG_NONE,
+ SEND_ATTR_INT(MAIL_ATTR_STATUS, status),
+ SEND_ATTR_STR(MAIL_ATTR_WHY,
+ (state->flags & CLEANUP_FLAG_SMTP_REPLY)
+ && state->smtp_reply ? state->smtp_reply :
+ state->reason ? state->reason : ""),
+ ATTR_TYPE_END);
+ cleanup_free(state);
+
+ /*
+ * Cleanup.
+ */
+ vstring_free(buf);
+}
+
+/* pre_accept - see if tables have changed */
+
+static void pre_accept(char *unused_name, char **unused_argv)
+{
+ const char *table;
+
+ if ((table = dict_changed_name()) != 0) {
+ msg_info("table %s has changed -- restarting", table);
+ exit(0);
+ }
+}
+
+MAIL_VERSION_STAMP_DECLARE;
+
+/* main - the main program */
+
+int main(int argc, char **argv)
+{
+
+ /*
+ * Fingerprint executables and core dumps.
+ */
+ MAIL_VERSION_STAMP_ALLOCATE;
+
+ /*
+ * Clean up an incomplete queue file in case of a fatal run-time error,
+ * or after receiving SIGTERM from the master at shutdown time.
+ */
+ signal(SIGTERM, cleanup_sig);
+ msg_cleanup(cleanup_all);
+
+ /*
+ * Pass control to the single-threaded service skeleton.
+ */
+ single_server_main(argc, argv, cleanup_service,
+ CA_MAIL_SERVER_INT_TABLE(cleanup_int_table),
+ CA_MAIL_SERVER_BOOL_TABLE(cleanup_bool_table),
+ CA_MAIL_SERVER_STR_TABLE(cleanup_str_table),
+ CA_MAIL_SERVER_TIME_TABLE(cleanup_time_table),
+ CA_MAIL_SERVER_PRE_INIT(cleanup_pre_jail),
+ CA_MAIL_SERVER_POST_INIT(cleanup_post_jail),
+ CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
+ CA_MAIL_SERVER_IN_FLOW_DELAY,
+ CA_MAIL_SERVER_UNLIMITED,
+ 0);
+}