-TBOUNCE_TIME_PARAMETER
-TCFG_PARSER
-TCIDR_MATCH
+-TCLEANUP_BODY_REGION
-TCLEANUP_STATE
-TCLEANUP_STAT_DETAIL
-TCLIENT_LIST
20070112
- Bugfix (introduced 20011008): with nested access restrictions,
- possible longjump into exited stack frame after configuration
- error or table lookup error. Victor Duchovni. Files:
- smtpd/smtpd_check.c.
-
- Horrible workaround: don't insert header/body blank line
- separator in malformed attachments. This breaks digital
- signatures. People concerned about MIME evasion can use a
- MIME normalizer to corrupt their user's legitimate email.
- File: global/mime_state.c.
+ Bugfix (introduced 20011008): after return from nested
+ access restriction, possible longjump into exited stack
+ frame upon configuration error or table lookup error. Victor
+ Duchovni. Files: smtpd/smtpd_check.c.
+
+ Workaround: don't insert header/body blank line separator
+ in malformed attachments, to avoid breaking digital signatures.
+ Switch from header to body state, for robust MIME parsing.
+ People concerned about MIME evasion can use a MIME normalizer
+ to corrupt their user's legitimate email. File:
+ global/mime_state.c.
+
+20070114
+
+ Feature: body replacement support for Milter applications.
+ Postfix 2.3 and older 2.4 versions will be able to deliver
+ body-replaced queue files, but will report the message size
+ as it was before the body was replaced. Files: milter/milter8.c,
+ cleanup/cleanup_milter.c, cleanup/cleanup_body_region.c.
Wish list:
(example: Domain keys). Having yet another Postfix-specific version of all that
software is a poor use of human and system resources.
-Postfix 2.3 implements all the requests of Sendmail version 8 Milter protocols
-up to version 4, except one: message body replacement. See, however, the
-workarounds and limitations sections at the end of this document.
+Postfix version 2.4 implements all the requests of Sendmail version 8 Milter
+protocols up to version 4, including message body replacement (body replacement
+is not available with Postfix version 2.3). See, however, the workarounds and
+limitations sections at the end of this document.
This document provides information on the following topics:
application name: st_optionneg[134563840]: 0x3d does not fulfill action
requirements 0x1e
- The solution is (to wait for) a Postfix version that supports the missing
+ The solution is to use a Postfix version that supports the missing
functionality.
* Most Milter configuration options are global. Future Postfix versions may
If you upgrade from Postfix 2.2 or earlier, read RELEASE_NOTES-2.3
before proceeding.
+Incompatible changes with Postfix snapshot 20070116
+===================================================
+
+A new field is added to the queue file "size" record that specifies
+the message content length. Postfix 2.3 and older Postfix 2.4
+versions will ignore this field, and will report the message size
+as it was before the body was replaced.
+
+Major changes with Postfix snapshot 20070116
+============================================
+
+Support for Milter applications that replace the message body.
+Postfix now implements all the header/body modification requests
+that are available with Sendmail 8.13.
+
Incompatible changes with Postfix snapshot 20061217
===================================================
Having yet another Postfix-specific version of all that software
is a poor use of human and system resources. </p>
-<p> Postfix 2.3 implements all the requests of Sendmail version 8
-Milter protocols up to version 4, except one: message body replacement.
+<p> Postfix version 2.4 implements all the requests of Sendmail
+version 8 Milter protocols up to version 4, including message body
+replacement (body replacement is not available with Postfix version
+2.3).
See, however, the <a href="#workarounds">workarounds</a> and <a
href="#limitations">limitations</a> sections at the end of this
document. </p>
</pre>
</blockquote>
-<p> The solution is (to wait for) a Postfix version that supports
-the missing functionality.
+<p> The solution is to use a Postfix version that supports the
+missing functionality. </p>
<li> <p> Most Milter configuration options are global. Future Postfix
versions may support per-Milter timeouts, per-Milter error handling,
Having yet another Postfix-specific version of all that software
is a poor use of human and system resources. </p>
-<p> Postfix 2.3 implements all the requests of Sendmail version 8
-Milter protocols up to version 4, except one: message body replacement.
+<p> Postfix version 2.4 implements all the requests of Sendmail
+version 8 Milter protocols up to version 4, including message body
+replacement (body replacement is not available with Postfix version
+2.3).
See, however, the <a href="#workarounds">workarounds</a> and <a
href="#limitations">limitations</a> sections at the end of this
document. </p>
</pre>
</blockquote>
-<p> The solution is (to wait for) a Postfix version that supports
-the missing functionality.
+<p> The solution is to use a Postfix version that supports the
+missing functionality. </p>
<li> <p> Most Milter configuration options are global. Future Postfix
versions may support per-Milter timeouts, per-Milter error handling,
cleanup_extracted.c cleanup_state.c cleanup_rewrite.c \
cleanup_map11.c cleanup_map1n.c cleanup_masquerade.c \
cleanup_out_recipient.c cleanup_init.c cleanup_api.c \
- cleanup_addr.c cleanup_bounce.c cleanup_milter.c
+ cleanup_addr.c cleanup_bounce.c cleanup_milter.c \
+ cleanup_body_region.c
OBJS = cleanup.o cleanup_out.o cleanup_envelope.o cleanup_message.o \
cleanup_extracted.o cleanup_state.o cleanup_rewrite.o \
cleanup_map11.o cleanup_map1n.o cleanup_masquerade.o \
cleanup_out_recipient.o cleanup_init.o cleanup_api.o \
- cleanup_addr.o cleanup_bounce.o cleanup_milter.o
+ cleanup_addr.o cleanup_bounce.o cleanup_milter.o \
+ cleanup_body_region.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
mv junk cleanup_masquerade.o
CLEANUP_MILTER_OBJS = cleanup_state.o cleanup_out.o cleanup_addr.o \
- cleanup_out_recipient.o
+ cleanup_out_recipient.o cleanup_body_region.o
cleanup_milter: cleanup_milter.o $(CLEANUP_MILTER_OBJS) $(LIBS)
mv cleanup_milter.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(CLEANUP_MILTER_OBJS) $(LIBS) $(SYSLIBS)
mv junk cleanup_milter.o
-tests: cleanup_masquerade_test cleanup_milter_test bug_tests \
+tests: cleanup_masquerade_test milter_tests
+
+milter_tests: cleanup_milter_test bug_tests \
cleanup_milter_test2 cleanup_milter_test3 cleanup_milter_test4 \
- cleanup_milter_test5 cleanup_milter_test6 cleanup_milter_test7
+ cleanup_milter_test5 cleanup_milter_test6 cleanup_milter_test7 \
+ cleanup_milter_test8 cleanup_milter_test9 cleanup_milter_test10a \
+ cleanup_milter_test10b cleanup_milter_test10c cleanup_milter_test10d \
+ cleanup_milter_test10e
root_tests:
./cleanup_milter <cleanup_milter.in6a
../postcat/postcat -ov test-queue-file6.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6a cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6b: cleanup_milter test-queue-file6 cleanup_milter.in6b \
cleanup_milter.ref6b test-queue-file6 ../postcat/postcat
./cleanup_milter <cleanup_milter.in6b
../postcat/postcat -ov test-queue-file6.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6b cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test6c: cleanup_milter test-queue-file6 cleanup_milter.in6c \
cleanup_milter.ref6c test-queue-file6 ../postcat/postcat
./cleanup_milter <cleanup_milter.in6c
../postcat/postcat -ov test-queue-file6.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref6c cleanup_milter.tmp
+ rm -f test-queue-file6.tmp cleanup_milter.tmp
cleanup_milter_test7: cleanup_milter test-queue-file7 cleanup_milter.in7 \
cleanup_milter.ref7 test-queue-file7 ../postcat/postcat
./cleanup_milter <cleanup_milter.in7
../postcat/postcat -ov test-queue-file7.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref7 cleanup_milter.tmp
+ rm -f test-queue-file7.tmp cleanup_milter.tmp
cleanup_milter_test8: cleanup_milter test-queue-file8 cleanup_milter.in8 \
cleanup_milter.ref8 test-queue-file8 ../postcat/postcat
./cleanup_milter <cleanup_milter.in8
../postcat/postcat -ov test-queue-file8.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref8 cleanup_milter.tmp
+ rm -f test-queue-file8.tmp cleanup_milter.tmp
cleanup_milter_test9: cleanup_milter test-queue-file9 cleanup_milter.in9 \
cleanup_milter.ref9 test-queue-file9 ../postcat/postcat
./cleanup_milter <cleanup_milter.in9
../postcat/postcat -ov test-queue-file9.tmp 2>/dev/null >cleanup_milter.tmp
diff cleanup_milter.ref9 cleanup_milter.tmp
+ rm -f test-queue-file9.tmp cleanup_milter.tmp
+
+cleanup_milter_test10a: cleanup_milter test-queue-file10 cleanup_milter.in10a \
+ cleanup_milter.ref10a test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter <cleanup_milter.in10a
+ ../postcat/postcat -ov test-queue-file10.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10a cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10b: cleanup_milter test-queue-file10 cleanup_milter.in10b \
+ cleanup_milter.ref10b test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter <cleanup_milter.in10b
+ ../postcat/postcat -ov test-queue-file10.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10b cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10c: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10c test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter <cleanup_milter.in10c
+ ../postcat/postcat -ov test-queue-file10.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10c cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10d: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10d test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter <cleanup_milter.in10d
+ ../postcat/postcat -ov test-queue-file10.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10d cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
+
+cleanup_milter_test10e: cleanup_milter test-queue-file10 cleanup_milter.in10c \
+ cleanup_milter.ref10e test-queue-file10 ../postcat/postcat
+ cp test-queue-file10 test-queue-file10.tmp
+ chmod u+w test-queue-file10.tmp
+ ./cleanup_milter <cleanup_milter.in10e
+ ../postcat/postcat -ov test-queue-file10.tmp 2>/dev/null >cleanup_milter.tmp
+ diff cleanup_milter.ref10e cleanup_milter.tmp
+ rm -f test-queue-file10.tmp cleanup_milter.tmp
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
cleanup_api.o: ../../include/msg_stats.h
cleanup_api.o: ../../include/mymalloc.h
cleanup_api.o: ../../include/nvtable.h
+cleanup_api.o: ../../include/rec_type.h
cleanup_api.o: ../../include/recipient_list.h
cleanup_api.o: ../../include/resolve_clnt.h
cleanup_api.o: ../../include/string_list.h
cleanup_api.o: ../../include/vstring.h
cleanup_api.o: cleanup.h
cleanup_api.o: cleanup_api.c
+cleanup_body_region.o: ../../include/argv.h
+cleanup_body_region.o: ../../include/been_here.h
+cleanup_body_region.o: ../../include/cleanup_user.h
+cleanup_body_region.o: ../../include/dict.h
+cleanup_body_region.o: ../../include/header_opts.h
+cleanup_body_region.o: ../../include/htable.h
+cleanup_body_region.o: ../../include/mail_conf.h
+cleanup_body_region.o: ../../include/mail_stream.h
+cleanup_body_region.o: ../../include/maps.h
+cleanup_body_region.o: ../../include/match_list.h
+cleanup_body_region.o: ../../include/match_ops.h
+cleanup_body_region.o: ../../include/milter.h
+cleanup_body_region.o: ../../include/mime_state.h
+cleanup_body_region.o: ../../include/msg.h
+cleanup_body_region.o: ../../include/mymalloc.h
+cleanup_body_region.o: ../../include/nvtable.h
+cleanup_body_region.o: ../../include/rec_type.h
+cleanup_body_region.o: ../../include/record.h
+cleanup_body_region.o: ../../include/resolve_clnt.h
+cleanup_body_region.o: ../../include/string_list.h
+cleanup_body_region.o: ../../include/sys_defs.h
+cleanup_body_region.o: ../../include/tok822.h
+cleanup_body_region.o: ../../include/vbuf.h
+cleanup_body_region.o: ../../include/vstream.h
+cleanup_body_region.o: ../../include/vstring.h
+cleanup_body_region.o: cleanup.h
+cleanup_body_region.o: cleanup_body_region.c
cleanup_bounce.o: ../../include/argv.h
cleanup_bounce.o: ../../include/attr.h
cleanup_bounce.o: ../../include/been_here.h
cleanup_extracted.o: cleanup_extracted.c
cleanup_init.o: ../../include/argv.h
cleanup_init.o: ../../include/been_here.h
+cleanup_init.o: ../../include/cleanup_user.h
cleanup_init.o: ../../include/dict.h
cleanup_init.o: ../../include/ext_prop.h
cleanup_init.o: ../../include/flush_clnt.h
cleanup_map1n.o: cleanup_map1n.c
cleanup_masquerade.o: ../../include/argv.h
cleanup_masquerade.o: ../../include/been_here.h
+cleanup_masquerade.o: ../../include/cleanup_user.h
cleanup_masquerade.o: ../../include/dict.h
cleanup_masquerade.o: ../../include/header_opts.h
cleanup_masquerade.o: ../../include/htable.h
cleanup_rewrite.o: ../../include/argv.h
cleanup_rewrite.o: ../../include/attr.h
cleanup_rewrite.o: ../../include/been_here.h
+cleanup_rewrite.o: ../../include/cleanup_user.h
cleanup_rewrite.o: ../../include/dict.h
cleanup_rewrite.o: ../../include/header_opts.h
cleanup_rewrite.o: ../../include/htable.h
cleanup_state.o: ../../include/argv.h
cleanup_state.o: ../../include/attr.h
cleanup_state.o: ../../include/been_here.h
+cleanup_state.o: ../../include/cleanup_user.h
cleanup_state.o: ../../include/dict.h
cleanup_state.o: ../../include/header_opts.h
cleanup_state.o: ../../include/htable.h
#include <mail_conf.h>
#include <mime_state.h>
#include <string_list.h>
+#include <cleanup_user.h>
/*
* Milter library.
void (*action) (struct CLEANUP_STATE *, int, const char *, ssize_t);
off_t data_offset; /* start of message content */
off_t xtra_offset; /* start of extra segment */
+ off_t cont_length; /* length including Milter edits */
off_t append_rcpt_pt_offset; /* append recipient here */
off_t append_rcpt_pt_target; /* target of above record */
off_t append_hdr_pt_offset; /* append header here */
#ifdef DELAY_ACTION
int defer_delay; /* deferred delivery */
#endif
+
+ /*
+ * Miscellaneous Milter support.
+ */
MILTERS *milters; /* mail filters */
const char *client_name; /* real or ersatz client */
const char *reverse_name; /* real or ersatz client */
const char *client_port; /* real or ersatz client */
VSTRING *milter_ext_from; /* externalized sender */
VSTRING *milter_ext_rcpt; /* externalized recipient */
+
+ /*
+ * Support for Milter body replacement requests.
+ */
+ struct CLEANUP_BODY_REGION *body_regions;
+ struct CLEANUP_BODY_REGION *curr_body_region;
+ off_t body_write_offs; /* body write position */
} CLEANUP_STATE;
/*
(((s)->flags & CLEANUP_FLAG_MILTER) != 0 \
&& (s)->errs == 0 && ((s)->flags & CLEANUP_FLAG_DISCARD) == 0)
+ /*
+ * cleanup_body_region.c
+ */
+typedef struct CLEANUP_BODY_REGION {
+ off_t start; /* start of region */
+ off_t len; /* length or zero (open-ended) */
+ struct CLEANUP_BODY_REGION *next;
+} CLEANUP_BODY_REGION;
+
+extern int cleanup_body_region_start(CLEANUP_STATE *);
+extern int cleanup_body_region_write(CLEANUP_STATE *, int, VSTRING *);
+extern int cleanup_body_region_finish(CLEANUP_STATE *);
+extern void cleanup_body_region_free(CLEANUP_STATE *);
+
/* LICENSE
/* .ad
/* .fi
#include <mail_params.h>
#include <mail_stream.h>
#include <mail_flow.h>
+#include <rec_type.h>
/* Milter library. */
int cleanup_flush(CLEANUP_STATE *state)
{
+ const char *myname = "cleanup_flush";
int status;
char *junk;
VSTRING *trace_junk;
}
}
+ /*
+ * Update the preliminary message size and count fields with the actual
+ * values.
+ *
+ * XXX This ugly code was moved up here from a lower-level module.
+ */
+ 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,
+ (REC_TYPE_SIZE_CAST1) (state->xtra_offset - state->data_offset),
+ (REC_TYPE_SIZE_CAST2) state->data_offset,
+ (REC_TYPE_SIZE_CAST3) state->rcpt_count,
+ (REC_TYPE_SIZE_CAST4) state->qmgr_opts,
+ (REC_TYPE_SIZE_CAST5) state->cont_length);
+
/*
* If there was an error that requires us to generate a bounce message
* (mail submitted with the Postfix sendmail command, mail forwarded by
--- /dev/null
+/*++
+/* NAME
+/* cleanup_body_region 3
+/* SUMMARY
+/* manage body content regions
+/* SYNOPSIS
+/* #include "cleanup.h"
+/*
+/* int cleanup_body_region_start(state)
+/* CLEANUP_STATE *state;
+/*
+/* int cleanup_body_region_write(state, type, buf)
+/* CLEANUP_STATE *state;
+/* int type;
+/* VSTRING *buf;
+/*
+/* int cleanup_body_region_finish(state)
+/* CLEANUP_STATE *state;
+/*
+/* void cleanup_body_region_free(state)
+/* CLEANUP_STATE *state;
+/* DESCRIPTION
+/* This module maintains queue file regions with body content.
+/* Regions are created on the fly, and can be reused multiple
+/* times. This module must not be called until the queue file
+/* is complete.
+/*
+/* cleanup_body_region_start() performs initialization and
+/* sets the queue file write pointer to the start of the
+/* first body content segment.
+/*
+/* cleanup_body_region_write() adds a queue file record to the
+/* current queue file. When the current queue file region fills
+/* up, some other region is reused or a new one is created.
+/*
+/* cleanup_body_region_finish() makes some final adjustments
+/* after the last body content record is written.
+/*
+/* cleanup_body_region_free() frees up memory that was allocated
+/* by cleanup_body_region_start() and cleanup_body_region_write().
+/*
+/* Arguments:
+/* .IP state
+/* Queue file and message processing state. This state is updated
+/* as records are processed and as errors happen.
+/* .IP type
+/* Record type.
+/* .IP buf
+/* Record content.
+/* BUGS
+/* Currently, queue file region management is intertwined with
+/* body content management. Eventually the two should be
+/* decoupled, so that space freed up after body editing may
+/* be reused for header updates and vice versa.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <rec_type.h>
+#include <record.h>
+
+/* Application-specific. */
+
+#include <cleanup.h>
+
+#define LEN(s) VSTRING_LEN(s)
+
+/* cleanup_body_region_alloc - create body content region */
+
+static CLEANUP_BODY_REGION *cleanup_body_region_alloc(off_t start, off_t len)
+{
+ CLEANUP_BODY_REGION *rp;
+
+ rp = (CLEANUP_BODY_REGION *) mymalloc(sizeof(*rp));
+ rp->start = start;
+ rp->len = len;
+ rp->next = 0;
+
+ return (rp);
+}
+
+/* cleanup_body_region_free - destroy all body content regions */
+
+void cleanup_body_region_free(CLEANUP_STATE *state)
+{
+ CLEANUP_BODY_REGION *rp;
+ CLEANUP_BODY_REGION *next;
+
+ for (rp = state->body_regions; rp != 0; rp = next) {
+ next = rp->next;
+ myfree((char *) rp);
+ }
+}
+
+/* cleanup_body_region_start - rewrite body buffer pool */
+
+int cleanup_body_region_start(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_body_region_write";
+
+ /*
+ * Calculate the payload size sans body.
+ */
+ state->cont_length = state->append_hdr_pt_target - state->data_offset;
+
+ /*
+ * Craft the first body region on the fly, from circumstantial evidence.
+ */
+ if (state->body_regions == 0)
+ state->body_regions =
+ cleanup_body_region_alloc(state->append_hdr_pt_target,
+ state->xtra_offset - state->append_hdr_pt_target);
+
+ /*
+ * Select the first region and initialize the write position.
+ */
+ state->curr_body_region = state->body_regions;
+ state->body_write_offs = state->curr_body_region->start;
+
+ /*
+ * Move the file write pointer to the start of the current region.
+ */
+ if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ return (0);
+}
+
+/* cleanup_body_region_write - add record to body buffer pool */
+
+int cleanup_body_region_write(CLEANUP_STATE *state, int rec_type,
+ VSTRING *buf)
+{
+ const char *myname = "cleanup_body_region_write";
+ CLEANUP_BODY_REGION *rp = state->curr_body_region;
+ off_t used;
+ ssize_t rec_len;
+ off_t start;
+
+ if (msg_verbose)
+ msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
+ myname, (long) state->body_write_offs, (long) LEN(buf),
+ (long) rp->start, (long) rp->len);
+
+ /*
+ * Switch to the next body region if we filled up the current one (we
+ * always append to an open-ended region). Besides space to write the
+ * specified record, we need to leave space for a final pointer record
+ * that will link this body region to the next region or to the content
+ * terminator record.
+ */
+ REC_SPACE_NEED(LEN(buf), rec_len);
+ if (rp->len > 0 && (used = state->body_write_offs - rp->start,
+ rec_len + REC_TYPE_PTR_SIZE > rp->len - used)) {
+
+ /*
+ * Allocate a new body region if we filled up the last one. A newly
+ * allocated region sits at the end of the queue file, and therefore
+ * it starts as open ended. We freeze the region size later.
+ *
+ * Don't use fstat() to figure out where the queue file ends, in case
+ * file sizes have magic in them. Instead we seek to the end and then
+ * back to where we were. We're not switching body regions often, so
+ * this is not performance critical.
+ */
+ if (rp->next == 0) {
+ if ((start = vstream_fseek(state->dst, (off_t) 0, SEEK_END)) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ if (vstream_fseek(state->dst, state->body_write_offs, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ rp->next = cleanup_body_region_alloc(start, 0);
+ }
+
+ /*
+ * Update the payload size and select the new body region.
+ */
+ state->cont_length += state->body_write_offs - rp->start;
+ state->curr_body_region = rp = rp->next;
+
+ /*
+ * Connect the filled up body region to its successor. By design a
+ * region has always space for a final pointer record.
+ */
+ if (msg_verbose)
+ msg_info("%s: link %ld -> %ld", myname,
+ (long) state->body_write_offs, (long) rp->start);
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) rp->start);
+ if (vstream_fseek(state->dst, rp->start, SEEK_SET) < 0) {
+ msg_warn("%s: seek file %s: %m", myname, cleanup_path);
+ return (-1);
+ }
+ }
+
+ /*
+ * Finally, output the queue file record.
+ */
+ CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
+ state->body_write_offs = vstream_ftell(state->dst);
+
+ return (0);
+}
+
+/* cleanup_body_region_finish - wrap up body buffer pool */
+
+int cleanup_body_region_finish(CLEANUP_STATE *state)
+{
+ const char *myname = "cleanup_body_region_finish";
+ CLEANUP_BODY_REGION *rp;
+
+ /*
+ * Link the last body region to the content terminator record.
+ */
+ rec_fprintf(state->dst, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT,
+ (long) state->xtra_offset);
+ state->body_write_offs = vstream_ftell(state->dst);
+
+ /*
+ * Update the payload size.
+ */
+ rp = state->curr_body_region;
+ state->cont_length += state->body_write_offs - rp->start;
+
+ /*
+ * Freeze the size of the last region if it is still open ended. The next
+ * Milter application may append more header records, therefore we must
+ * not assume that this region can grow further. Nor can we truncate the
+ * queue file to the end of this region, as this region may be followed
+ * by headers that were appended by an earlier Milter application.
+ *
+ * XXX Eventually, split a partially-used region so that the remainder can
+ * be returned to a free pool and reused for header updates.
+ */
+ if (rp->len == 0)
+ rp->len = state->body_write_offs - rp->start;
+ if (msg_verbose)
+ msg_info("%s: freeze start %ld len %ld",
+ myname, (long) rp->start, (long) rp->len);
+
+ return (CLEANUP_OUT_OK(state) ? 0 : -1);
+}
* first, for backwards compatibility reasons.
*/
cleanup_out_format(state, REC_TYPE_SIZE, REC_TYPE_SIZE_FORMAT,
- (REC_TYPE_SIZE_CAST1) 0, /* content size */
+ (REC_TYPE_SIZE_CAST1) 0, /* extra offs - content offs */
(REC_TYPE_SIZE_CAST2) 0, /* content offset */
(REC_TYPE_SIZE_CAST3) 0, /* recipient count */
- (REC_TYPE_SIZE_CAST4) 0); /* qmgr options */
+ (REC_TYPE_SIZE_CAST4) 0, /* qmgr options */
+ (REC_TYPE_SIZE_CAST5) 0); /* content length */
/*
* Pass control to the actual envelope processing routine.
}
return;
}
-
- /*
- * Update the preliminary message size and count fields with the actual
- * values.
- */
- 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,
- (REC_TYPE_SIZE_CAST1) (state->xtra_offset - state->data_offset),
- (REC_TYPE_SIZE_CAST2) state->data_offset,
- (REC_TYPE_SIZE_CAST3) state->rcpt_count,
- (REC_TYPE_SIZE_CAST4) state->qmgr_opts);
}
state->mime_state = mime_state_free(state->mime_state);
if ((state->xtra_offset = vstream_ftell(state->dst)) < 0)
msg_fatal("%s: vstream_ftell %s: %m", myname, cleanup_path);
+ state->cont_length = state->xtra_offset - state->data_offset;
state->action = cleanup_extracted;
}
/* cleanup_repl_body - replace message body */
-static const char *cleanup_repl_body(void *context, VSTRING *body)
+static const char *cleanup_repl_body(void *context, int cmd, VSTRING *buf)
{
const char *myname = "cleanup_repl_body";
+ CLEANUP_STATE *state = (CLEANUP_STATE *) context;
+ static VSTRING empty;
/*
* XXX Sendmail compatibility: milters don't see the first body line, so
* don't expect they will send one.
*/
- msg_panic("%s: message body replace operation is not implemented", myname);
+ switch (cmd) {
+ case MILTER_BODY_LINE:
+ if (cleanup_body_region_write(state, REC_TYPE_NORM, buf) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ case MILTER_BODY_START:
+ VSTRING_RESET(&empty);
+ if (cleanup_body_region_start(state) < 0
+ || cleanup_body_region_write(state, REC_TYPE_NORM, &empty) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ case MILTER_BODY_END:
+ if (cleanup_body_region_finish(state) < 0)
+ return (cleanup_milter_error(state, errno));
+ break;
+ default:
+ msg_panic("%s: bad command: %d", myname, cmd);
+ }
+ return (CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, errno));
}
/* cleanup_milter_eval - expand macro */
}
}
}
+ if (state->append_rcpt_pt_offset < 0)
+ msg_fatal("file %s: no append recipient pointer record",
+ cleanup_path);
+ if (state->append_hdr_pt_offset < 0)
+ msg_fatal("file %s: no append header pointer record",
+ cleanup_path);
if (msg_verbose) {
msg_info("append_rcpt_pt_offset %ld append_rcpt_pt_target %ld",
(long) state->append_rcpt_pt_offset,
vstream_printf("- ");
vstream_fflush(VSTREAM_OUT);
}
- if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
+ if (vstring_fgets_nonl(inbuf, VSTREAM_IN) == 0)
break;
bufp = vstring_str(inbuf);
} else {
cleanup_del_rcpt(state, argv->argv[1]);
}
+ } else if (strcmp(argv->argv[0], "replbody") == 0) {
+ if (argv->argc != 2) {
+ msg_warn("bad replbody argument count: %d", argv->argc);
+ } else {
+ VSTREAM *fp;
+ VSTRING *buf;
+
+ if ((fp = vstream_fopen(argv->argv[1], O_RDONLY, 0)) == 0) {
+ msg_warn("open %s file: %m", argv->argv[1]);
+ } else {
+ buf = vstring_alloc(100);
+ cleanup_repl_body(state, MILTER_BODY_START, buf);
+ while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
+ cleanup_repl_body(state, MILTER_BODY_LINE, buf);
+ cleanup_repl_body(state, MILTER_BODY_END, buf);
+ vstring_free(buf);
+ vstream_fclose(fp);
+ }
+ }
} else {
msg_warn("bad command: %s", argv->argv[0]);
}
--- /dev/null
+#
+# Replace a short body by a longer one. The result is two body
+# regions: the original region with the head of the new text, and
+# one region at the end of the queue file with the remainder of the
+# new text.
+#
+open test-queue-file10.tmp
+
+replbody loremipsum
+
+close
--- /dev/null
+#
+# Replace a short body by a longer one, and then replace the longer
+# body by itself. The result should be identical to what we had after
+# one replacement.
+#
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum
+
+close
--- /dev/null
+#
+# Replace a short body by a longer one, and then clobber that with
+# an even longer body. The result is three body regions: the original
+# region, the region that contained the tail of the first replacement,
+# and a region that contains the tail of the second replacement.
+#
+
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum2
+
+close
--- /dev/null
+#
+# As test 10c, but then replace the longer body by the shorter one. The
+# result is three regions: the original region, the region with the
+# tail of the shorter replacement, and an unused region that contained
+# the tail of the larger region.
+#
+#verbose on
+open test-queue-file10.tmp
+
+replbody loremipsum
+replbody loremipsum2
+replbody loremipsum
+
+close
--- /dev/null
+#
+# Replace a short body by increasingly longer ones and do header
+# updates in between.
+#
+#verbose on
+open test-queue-file10.tmp
+
+add_header foo1 foobar
+replbody loremipsum
+add_header foo2 foobar
+replbody loremipsum2
+
+close
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1434 regular_text: pariatur?\r
+ 1446 regular_text: \r
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1434 regular_text: pariatur?\r
+ 1446 regular_text: \r
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1434 regular_text: pariatur?\r
+ 1446 regular_text: \r
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2320 pointer_record: 2337
+ 2337 regular_text: \r
+ 2340 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 2405 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 2472 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 2540 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 2609 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 2678 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 2744 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 2812 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 2879 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 2944 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 3018 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 3087 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 3155 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 3222 regular_text: pariatur?\r
+ 3234 regular_text: \r
+ 3237 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 3302 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 3367 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 3435 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 3502 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 3573 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 3640 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 3707 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 3776 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 3846 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 3912 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 3981 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 4047 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 4108 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 0
+ 485 regular_text:
+ 487 pointer_record: 552
+ 552 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1434 regular_text: pariatur?\r
+ 1446 regular_text: \r
+ 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2320 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
--- /dev/null
+*** ENVELOPE RECORDS test-queue-file10.tmp ***
+ 0 message_size: 329 181 1 0
+ 65 message_arrival_time: Tue Jul 25 15:37:06 2006
+ 82 create_time: Tue Jul 25 15:37:06 2006
+ 106 named_attribute: rewrite_context=local
+ 129 sender_fullname: Wietse Venema
+ 144 sender: me@porcupine.org
+ 162 pointer_record: 0
+ 179 *** MESSAGE CONTENTS test-queue-file10.tmp ***
+ 181 regular_text: Received: by bristle.watson.ibm.com (Postfix, from userid 0)
+ 243 regular_text: id 034B229013F; Tue, 25 Jul 2006 15:37:06 -0400 (EDT)
+ 299 regular_text: From: me@porcupine.org
+ 323 regular_text: To: you@porcupine.org
+ 346 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+ 408 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+ 453 regular_text: Subject: hey!
+ 468 pointer_record: 552
+ 552 regular_text: foo1: foobar
+ 566 pointer_record: 2368
+ 2368 regular_text: foo2: foobar
+ 2382 pointer_record: 485
+ 485 regular_text:
+ 487 pointer_record: 583
+ 583 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 648 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 715 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 783 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 852 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 921 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 987 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 1055 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 1122 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 1187 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 1261 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 1330 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 1398 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 1465 regular_text: pariatur?\r
+ 1477 regular_text: \r
+ 1480 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 1545 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 1610 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 1678 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 1745 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 1816 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 1883 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 1950 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 2019 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 2089 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 2155 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 2224 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 2290 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 2351 pointer_record: 2399
+ 2399 regular_text: \r
+ 2402 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+ 2467 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+ 2534 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+ 2602 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+ 2671 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+ 2740 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+ 2806 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+ 2874 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+ 2941 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+ 3006 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+ 3080 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+ 3149 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+ 3217 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+ 3284 regular_text: pariatur?\r
+ 3296 regular_text: \r
+ 3299 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+ 3364 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+ 3429 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non\r
+ 3497 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia\r
+ 3564 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+ 3635 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+ 3702 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+ 3769 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+ 3838 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+ 3908 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+ 3974 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+ 4043 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+ 4109 regular_text: consequatur aut perferendis doloribus asperiores repellat.\r
+ 4170 pointer_record: 510
+ 510 *** HEADER EXTRACTED test-queue-file10.tmp ***
+ 512 original_recipient: you@porcupine.org
+ 531 recipient: you@porcupine.org
+ 550 *** MESSAGE FILE END test-queue-file10.tmp ***
state->action = cleanup_envelope;
state->data_offset = -1;
state->xtra_offset = -1;
+ state->cont_length = 0;
state->append_rcpt_pt_offset = -1;
state->append_rcpt_pt_target = -1;
state->append_hdr_pt_offset = -1;
state->client_port = 0;
state->milter_ext_from = 0;
state->milter_ext_rcpt = 0;
+ state->body_regions = state->curr_body_region = 0;
return (state);
}
vstring_free(state->milter_ext_from);
if (state->milter_ext_rcpt)
vstring_free(state->milter_ext_rcpt);
+ if (state->body_regions)
+ cleanup_body_region_free(state);
myfree((char *) state);
}
--- /dev/null
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+pariatur?\r
+\r
+At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+dolores et quas molestias excepturi sint occaecati cupiditate non\r
+provident, similique sunt in culpa qui officia deserunt mollitia\r
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+consequatur aut perferendis doloribus asperiores repellat.\r
--- /dev/null
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+pariatur?\r
+\r
+At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+dolores et quas molestias excepturi sint occaecati cupiditate non\r
+provident, similique sunt in culpa qui officia deserunt mollitia\r
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+consequatur aut perferendis doloribus asperiores repellat.\r
+\r
+Sed ut perspiciatis unde omnis iste natus error sit voluptatem\r
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa\r
+quae ab illo inventore veritatis et quasi architecto beatae vitae\r
+dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\r
+aspernatur aut odit aut fugit, sed quia consequuntur magni dolores\r
+eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam\r
+est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci\r
+velit, sed quia non numquam eius modi tempora incidunt ut labore\r
+et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima\r
+veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam,\r
+nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure\r
+reprehenderit qui in ea voluptate velit esse quam nihil molestiae\r
+consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla\r
+pariatur?\r
+\r
+At vero eos et accusamus et iusto odio dignissimos ducimus qui\r
+blanditiis praesentium voluptatum deleniti atque corrupti quos\r
+dolores et quas molestias excepturi sint occaecati cupiditate non\r
+provident, similique sunt in culpa qui officia deserunt mollitia\r
+animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis\r
+est et expedita distinctio. Nam libero tempore, cum soluta nobis\r
+est eligendi optio cumque nihil impedit quo minus id quod maxime\r
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor\r
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut\r
+rerum necessitatibus saepe eveniet ut et voluptates repudiandae\r
+sint et molestiae non recusandae. Itaque earum rerum hic tenetur a\r
+sapiente delectus, ut aut reiciendis voluptatibus maiores alias\r
+consequatur aut perferendis doloribus asperiores repellat.\r
namadr_list_test mail_conf_time_test
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
- mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3
+ mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
root_tests: rewrite_clnt_test resolve_clnt_test
diff mime_garb3.ref mime_cvt.tmp
rm -f mime_cvt.tmp
+mime_garb4: mime_state mime_garb4.in mime_garb4.ref
+ ./mime_state <mime_garb4.in >mime_cvt.tmp
+ diff mime_garb4.ref mime_cvt.tmp
+ rm -f mime_cvt.tmp
+
tok822_limit_test: tok822_parse tok822_limit.in tok822_limit.ref
./tok822_parse <tok822_limit.in >tok822_limit.tmp
diff tok822_limit.ref tok822_limit.tmp
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20070113"
+#define MAIL_RELEASE_DATE "20070116"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
boundary="Boundary-00=_mvhpFky0yqNhsa4"
HEADER END
mime_state: garbage in primary header
-BODY N -1 |
+BODY N 0 |
BODY N 0 |junk in primary header
BODY N 23 |
BODY N 24 |--Boundary-00=_mvhpFky0yqNhsa4
--- /dev/null
+From: Some One <user@example.com>
+To: Some One <user@example.com>
+Subject: Test
+MIME-Version: 1.0
+Content-Type: Multipart/Mixed;
+ boundary="top-level-boundary"
+
+--top-level-boundary
+Content-Type: message/rfc822;
+ name="forwarded message"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+To: user@example.com
+=46rom: Some One <user@example.com>
+Subject: Forwarded Test
+Content-Type: Multipart/Mixed;
+ boundary=3D"nested-level-boundary"
+
+--nested-level-boundary
+Content-Type: text/plain;
+Content-Transfer-Encoding: quoted-printable
+
+Blah
+
+--nested-level-boundary--
+
+--top-level-boundary
+Content-Type: text/plain;
+ charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+This is a test
--- /dev/null
+MAIN 0 |From: Some One <user@example.com>
+MAIN 32 |To: Some One <user@example.com>
+MAIN 46 |Subject: Test
+MAIN 64 |MIME-Version: 1.0
+mime_state: header_token: Multipart / Mixed
+mime_state: header_token: boundary = top-level-boundary
+mime_state: PUSH boundary top-level-boundary
+MAIN 95 |Content-Type: Multipart/Mixed;
+ boundary="top-level-boundary"
+HEADER END
+BODY N 0 |
+BODY N 1 |--top-level-boundary
+mime_state: header_token: message / rfc822
+MULT 0 |Content-Type: message/rfc822;
+ name="forwarded message"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+mime_state: warning: invalid message/* or multipart/* encoding domain: quoted-printable
+BODY N 0 |
+NEST 0 |To: user@example.com
+NEST 36 |=46rom: Some One <user@example.com>
+NEST 60 |Subject: Forwarded Test
+mime_state: header_token: Multipart / Mixed
+mime_state: header_token: boundary = 3D
+mime_state: PUSH boundary 3D
+NEST 91 |Content-Type: Multipart/Mixed;
+ boundary=3D"nested-level-boundary"
+BODY N 0 |
+BODY N 1 |--nested-level-boundary
+BODY N 25 |Content-Type: text/plain;
+BODY N 51 |Content-Transfer-Encoding: quoted-printable
+BODY N 95 |
+BODY N 96 |Blah
+BODY N 101 |
+BODY N 102 |--nested-level-boundary--
+BODY N 128 |
+mime_state: POP boundary 3D
+BODY N 129 |--top-level-boundary
+mime_state: header_token: text / plain
+MULT 0 |Content-Type: text/plain;
+ charset="utf-8"
+mime_state: header_token: quoted-printable
+MULT 44 |Content-Transfer-Encoding: quoted-printable
+MULT 72 |Content-Disposition: inline
+BODY N 0 |
+BODY N 1 |This is a test
+BODY END
+mime_state: warning: improper message/* or multipart/* encoding domain
+mime_state: POP boundary top-level-boundary
/* Volatile members. */
state->err_flags = 0;
+ state->body_offset = 0; /* XXX */
SET_MIME_STATE(state, MIME_STATE_PRIMARY,
MIME_CTYPE_TEXT, MIME_STYPE_PLAIN,
MIME_ENC_7BIT, MIME_ENC_7BIT);
* messages. Otherwise, treat such headers as part of the "body". Set
* the proper encoding information for the multipart prolog.
*
+ * XXX We parse headers inside message/* content even when the encoding
+ * is invalid (encoding != domain). With base64 we won't recognize
+ * any headers, and with quoted-printable we won't recognize MIME
+ * boundary strings, but the MIME processor will still resynchronize
+ * when it runs into the higher-level boundary string at the end of
+ * the message/* content. Although we will treat some headers as body
+ * text, we will still do a better job than if we were treating the
+ * entire message/* content as body text.
+ *
* XXX This changes state to MIME_STATE_NESTED and then outputs a body
* line, so that the body offset is not properly reset.
*
* separator, nor does the Milter protocol pass it on to Milter
* applications.
*
- * XXX We don't insert a blank line separator with attachments, as
- * this breaks digital signatures. Postfix shall not do a worse
- * mail delivery job than crappy MTAs that can't even parse MIME.
- * But we switch to the body state anyway.
+ * XXX We don't insert a blank line separator into attachments, to
+ * avoid breaking digital signatures. Postfix shall not do a
+ * worse mail delivery job than MTAs that can't even parse MIME.
+ * We switch to body state anyway, to avoid treating body text as
+ * header text, and mis-interpreting or truncating it. The code
+ * below for initial From_ lines is for educational purposes.
*
- * People who worry about MIME evasion can use a MIME normalizer,
- * and knowlingly corrupt legitimate email for their users.
+ * Sites concerned about MIME evasion can use a MIME normalizer.
* Postfix has a different mission.
*/
else {
state->curr_state == MIME_STATE_PRIMARY ? "primary" :
state->curr_state == MIME_STATE_NESTED ? "nested" :
"other");
- if (state->curr_state == MIME_STATE_PRIMARY)
+ switch (state->curr_state) {
+ case MIME_STATE_PRIMARY:
BODY_OUT(state, REC_TYPE_NORM, "", 0);
- SET_CURR_STATE(state, MIME_STATE_BODY);
+ SET_CURR_STATE(state, MIME_STATE_BODY);
+ break;
+#if 0
+ case MIME_STATE_NESTED:
+ if (state->body_offset <= 1
+ && rec_type == REC_TYPE_NORM
+ && len > 7
+ && (strncmp(text + (*text == '>'), "From ", 5) == 0
+ || strncmp(text, "=46rom ", 7) == 0))
+ break;
+ /* FALLTHROUGH */
+#endif
+ default:
+ SET_CURR_STATE(state, MIME_STATE_BODY);
+ break;
+ }
}
}
*
* See also: REC_TYPE_PTR_FORMAT below.
*/
-#define REC_TYPE_SIZE_FORMAT "%15ld %15ld %15ld %15ld"
-#define REC_TYPE_SIZE_CAST1 long
-#define REC_TYPE_SIZE_CAST2 long /* Postfix 1.0, a.k.a. 20010228 */
-#define REC_TYPE_SIZE_CAST3 long /* Postfix 1.0, a.k.a. 20010228 */
-#define REC_TYPE_SIZE_CAST4 long /* Postfix 2.1 */
+#define REC_TYPE_SIZE_FORMAT "%15ld %15ld %15ld %15ld %15ld"
+#define REC_TYPE_SIZE_CAST1 long /* Vmailer extra offs - data offs */
+#define REC_TYPE_SIZE_CAST2 long /* Postfix 1.0 data offset */
+#define REC_TYPE_SIZE_CAST3 long /* Postfix 1.0 recipient count */
+#define REC_TYPE_SIZE_CAST4 long /* Postfix 2.1 qmgr flags */
+#define REC_TYPE_SIZE_CAST5 long /* Postfix 2.4 content length */
/*
* The warn record specifies when the next warning that the message was
/* int rec_goto(stream, where)
/* VSTREAM *stream;
/* const char *where;
+/*
+/* REC_SPACE_NEED(buflen, reclen)
+/* ssize_t buflen;
+/* ssize_t reclen;
/* DESCRIPTION
/* This module reads and writes typed variable-length records.
/* Each record contains a 1-byte type code (0..255), a length
/* the file pointer to the specified location. A zero position
/* means do nothing. The result is REC_TYPE_ERROR in case of
/* failure.
+/*
+/* REC_SPACE_NEED(buflen, reclen) converts the specified buffer
+/* length into a record length. This macro modifies its second
+/* argument.
/* DIAGNOSTICS
/* Panics: interface violations. Fatal errors: insufficient memory.
/* Warnings: corrupted file.
#define REC_PUT_BUF(v, t, b) rec_put((v), (t), vstring_str(b), VSTRING_LEN(b))
-#define REC_FLAG_NONE (0)
+#define REC_FLAG_NONE (0)
#define REC_FLAG_FOLLOW_PTR (1<<0) /* follow PTR records */
#define REC_FLAG_SKIP_DTXT (1<<1) /* skip DTXT records */
#define REC_FLAG_SEEK_END (1<<2) /* seek EOF after END record */
#define rec_get(fp, buf, limit) \
rec_get_raw((fp), (buf), (limit), REC_FLAG_DEFAULT)
+#define REC_SPACE_NEED(buflen, reclen) do { \
+ ssize_t _c, _l; \
+ for (_c = 1, _l = (buflen); _l != 0; _l >>= 7U, _c++) \
+ ; \
+ (reclen) = 1 + _c + (buflen); \
+ } while (0)
+
/*
* Stuff that needs <stdarg.h>
*/
const char *(*del_header) (void *, ssize_t, char *),
const char *(*add_rcpt) (void *, char *),
const char *(*del_rcpt) (void *, char *),
- const char *(*repl_body) (void *, VSTRING *),
+ const char *(*repl_body) (void *, int, VSTRING *),
void *chg_context)
{
milters->add_header = add_header;
const char *(*ins_header) (void *, ssize_t, char *, char *);
const char *(*add_rcpt) (void *, char *);
const char *(*del_rcpt) (void *, char *);
- const char *(*repl_body) (void *, VSTRING *);
+ const char *(*repl_body) (void *, int, VSTRING *);
} MILTERS;
typedef const char *(*MILTER_MAC_LOOKUP_FN) (const char *, void *);
typedef const char *(*MILTER_EDIT_HEADER_FN) (void *, ssize_t, char *, char *);
typedef const char *(*MILTER_DEL_HEADER_FN) (void *, ssize_t, char *);
typedef const char *(*MILTER_EDIT_RCPT_FN) (void *, char *);
-typedef const char *(*MILTER_EDIT_BODY_FN) (void *, VSTRING *);
+typedef const char *(*MILTER_EDIT_BODY_FN) (void *, int, VSTRING *);
extern MILTERS *milter_create(const char *, int, int, int,
const char *, const char *,
extern MILTERS *milter_receive(VSTREAM *, int);
extern void milter_free(MILTERS *);
+ /*
+ * Milter body edit commands.
+ */
+#define MILTER_BODY_START 1 /* start message body */
+#define MILTER_BODY_LINE 2 /* message body line */
+#define MILTER_BODY_END 3 /* end message body */
+
/*
* Sendmail 8 macro names. We support forms with and without the {}.
*/
/* Global library. */
+#include <mail_params.h> /* var_line_limit */
#include <mail_proto.h>
#include <rec_type.h>
#include <record.h>
ssize_t data_size;
const char *smfic_name;
const char *smfir_name;
- MILTERS *parent;
+ MILTERS *parent = milter->m.parent;
UINT32_TYPE index;
- const char *edit_resp;
+ const char *edit_resp = 0;
+ const char *retval = 0;
+ VSTRING *body_line_buf = 0;
+ int done = 0;
#define DONT_SKIP_REPLY 0
/*
* Receive the reply or replies.
*
+ * Intercept all loop exits so that we can do post body replacement
+ * processing.
+ *
* XXX Bound the loop iteration count.
*/
#define IN_CONNECT_EVENT(e) ((e) == SMFIC_CONNECT || (e) == SMFIC_HELO)
- for (;;) {
+ /*
+ * XXX Don't evaluate this macro's argument multiple times. Since we use
+ * "continue" the macro can't be enclosed in do .. while (0).
+ */
+#define MILTER8_EVENT_BREAK(s) { \
+ retval = (s); \
+ done = 1; \
+ continue; \
+ }
+
+ while (done == 0) {
char *cp;
char *rp;
char ch;
if (milter8_read_resp(milter, event, &cmd, &data_size) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if (msg_verbose)
msg_info("reply: %s data %ld bytes",
(smfir_name = str_name_code(smfir_table, cmd)) != 0 ?
case SMFIR_CONTINUE:
if (data_size != 0)
break;
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
/*
* Decision: accept this message, or accept all further commands
/* No more events for this message. */
milter->state = MILTER8_STAT_ACCEPT_MSG;
}
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
/*
* Decision: accept and silently discard this message. According
msg_warn("milter %s: DISCARD action is not allowed "
"for connect or helo", milter->m.name);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
} else {
/* No more events for this message. */
milter->state = MILTER8_STAT_ACCEPT_MSG;
- return ("D");
+ MILTER8_EVENT_BREAK("D");
}
/*
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, "550 5.7.1 Command rejected"));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, "550 5.7.1 Command rejected"));
} else {
- return ("550 5.7.1 Command rejected");
+ MILTER8_EVENT_BREAK("550 5.7.1 Command rejected");
}
/*
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter,
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter,
"451 4.7.1 Service unavailable - try again later"));
} else {
- return ("451 4.7.1 Service unavailable - try again later");
+ MILTER8_EVENT_BREAK("451 4.7.1 Service unavailable - try again later");
}
/*
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, "S"));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, "S"));
#endif
/*
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if ((STR(milter->buf)[0] != '4' && STR(milter->buf)[0] != '5')
|| !ISDIGIT(STR(milter->buf)[1])
|| !ISDIGIT(STR(milter->buf)[2])
msg_warn("milter %s: malformed reply: %s",
milter->m.name, STR(milter->buf));
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if ((rp = cp = strchr(STR(milter->buf), '%')) != 0) {
for (;;) {
milter8_close_stream(milter);
#endif
milter->state = MILTER8_STAT_REJECT_CON;
- return (milter8_def_reply(milter, STR(milter->buf)));
+ MILTER8_EVENT_BREAK(milter8_def_reply(milter, STR(milter->buf)));
} else {
- return (STR(milter->buf));
+ MILTER8_EVENT_BREAK(STR(milter->buf));
}
/*
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- return ("H");
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ MILTER8_EVENT_BREAK("H");
#endif
/*
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
/* XXX Sendmail 8 compatibility. */
if (index == 0)
index = 1;
msg_warn("milter %s: bad change header index: %ld",
milter->m.name, (long) index);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if (LEN(milter->buf) == 0) {
msg_warn("milter %s: null change header name",
milter->m.name);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
if (STR(milter->body)[0])
edit_resp = parent->upd_header(parent->chg_context,
(ssize_t) index,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
#endif
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->add_header(parent->chg_context,
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_STRING, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
if ((ssize_t) index + 1 < 1) {
msg_warn("milter %s: bad insert header index: %ld",
milter->m.name, (long) index);
milter8_conf_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
- parent = milter->m.parent;
edit_resp = parent->ins_header(parent->chg_context,
(ssize_t) index + 1,
STR(milter->buf),
STR(milter->body));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
#endif
if (milter8_read_data(milter, data_size,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->add_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
if (milter8_read_data(milter, data_size,
MILTER8_DATA_STRING, milter->buf,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
+ MILTER8_EVENT_BREAK(milter->def_reply);
edit_resp = parent->del_rcpt(parent->chg_context,
STR(milter->buf));
if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(edit_resp);
continue;
/*
* Modification request: replace the message body, and
* update the message size.
*/
-#if 0
case SMFIR_REPLBODY:
if (milter8_read_data(milter, data_size,
MILTER8_DATA_BUFFER, milter->body,
MILTER8_DATA_END) != 0)
- return (milter->def_reply);
- parent = milter->m.parent;
- edit_resp = parent->repl_body(parent->chg_context,
- milter->body);
- if (edit_resp)
- return (edit_resp);
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ /* Start body replacement. */
+ if (body_line_buf == 0) {
+ body_line_buf = vstring_alloc(var_line_limit);
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_START,
+ (VSTRING *) 0);
+ }
+ /* Extract lines from the on-the-wire CRLF format. */
+ for (cp = STR(milter->body); edit_resp == 0
+ && cp < vstring_end(milter->body); cp++) {
+ ch = *(unsigned char *) cp;
+ if (ch == '\n') {
+ if (LEN(body_line_buf) > 0
+ && vstring_end(body_line_buf)[-1] == '\r')
+ vstring_truncate(body_line_buf,
+ LEN(body_line_buf) - 1);
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_LINE,
+ body_line_buf);
+ VSTRING_RESET(body_line_buf);
+ } else {
+ VSTRING_ADDCH(body_line_buf, ch);
+ }
+ }
continue;
-#endif
}
}
msg_warn("milter %s: unexpected filter response %s after event %s",
(smfic_name = str_name_code(smfic_table, event)) != 0 ?
smfic_name : "(unknown MTA event)");
milter8_comm_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
}
/*
milter->m.name, (smfir_name = str_name_code(smfir_table, cmd)) != 0 ?
smfir_name : "unknown", (long) data_len);
milter8_comm_error(milter);
- return (milter->def_reply);
+ MILTER8_EVENT_BREAK(milter->def_reply);
+ }
+
+ /*
+ * Finish message body replacement.
+ */
+ if (body_line_buf != 0) {
+ if (edit_resp == 0) {
+ /* In case the last body replacement line didn't end in CRLF. */
+ if (LEN(body_line_buf) > 0)
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_LINE,
+ body_line_buf);
+ if (edit_resp == 0)
+ edit_resp = parent->repl_body(parent->chg_context,
+ MILTER_BODY_END,
+ (VSTRING *) 0);
+ }
+ vstring_free(body_line_buf);
+
+ /*
+ * Override a non-reject/discard result value after body replacement
+ * failure.
+ *
+ * XXX Some cleanup clients ask the cleanup server to bounce mail for
+ * them. In that case we must override a hard reject retval result
+ * after queue file update failure. This is not a big problem; the
+ * odds are small that a Milter application sends a hard reject after
+ * replacing the message body.
+ */
+ if (edit_resp && (retval == 0 || strchr("DS4", retval[0]) == 0))
+ retval = edit_resp;
}
+ return (retval);
}
/* milter8_connect - connect to filter */
int fd;
const UINT32_TYPE my_actions = (SMFIF_ADDHDRS | SMFIF_ADDRCPT
| SMFIF_DELRCPT | SMFIF_CHGHDRS
- /* Not yet: | SMFIF_CHGBODY */
+ | SMFIF_CHGBODY
#ifdef SMFIF_QUARANTINE
| SMFIF_QUARANTINE
#endif
return (milter->def_reply);
case MILTER8_STAT_ENVELOPE:
case MILTER8_STAT_ACCEPT_MSG:
+ /* With HELO after MAIL, smtpd(8) calls milter8_abort() next. */
if (msg_verbose)
msg_info("%s: milter %s: helo %s",
myname, milter->m.name, helo_name);
- /*
- * Simple test mail filter program.
- *
- * Options:
- *
- * -a accept|tempfail|reject|discard|ddd x.y.z text
- *
- * Specifies a non-default reply. The default is to always continue.
- *
- * -d Enable libmilter debugging.
- *
- * -c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort
- *
- * When to send the non-default reply. The default is "connect".
- *
- * -i "index header-label header-value"
- *
- * Insert header at specified position.
- *
- * -p inet:port@host|unix:/path/name
- *
- * The mail filter listen endpoint.
- *
- * -r "index header-label header-value"
- *
- * Replace header at specified position.
- *
- * -C count
- *
- * Terminate after count connections.
- */
+/*++
+/* NAME
+/* test-milter 1
+/* SUMMARY
+/* Simple test mail filter program.
+/* SYNOPSIS
+/* .fi
+/* \fBtest-milter\fR [\fIoptions\fR] -p \fBinet:\fIport\fB@\fIhost\fR
+/*
+/* \fBtest-milter\fR [\fIoptions\fR] -p \fBunix:\fIpathname\fR
+/* DESCRIPTION
+/* \fBtest-milter\fR is a Milter (mail filter) application that
+/* exercises selected features.
+/*
+/* Note: this is an unsupported test program. No attempt is made
+/* to maintain compatibility between successive versions.
+/*
+/* Arguments (multiple alternatives are separated by "\fB|\fR"):
+/* .IP "\fB-a accept|tempfail|reject|discard|\fIddd x.y.z text\fR"
+/* Specifies a non-default reply. The default is to continue
+/* (i.e. \fBtempfail\fR).
+/* .IP "\fB-d\fI level\fR"
+/* Enable libmilter debugging at the specified level.
+/* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
+/* When to send the non-default reply specified with \fB-a\fR.
+/* The default protocol stage is \fBconnect\fR.
+/* .IP "\fB-C\fI count\fR"
+/* Terminate after \fIcount\fR connections.
+/* .IP "\fB-i \"\fIindex header-label header-value\"\fR"
+/* Insert header at specified position.
+/* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR"
+/* The mail filter listen endpoint.
+/* .IP "\fB-r "index header-label header-value"
+/* Replace the message header at the specified position.
+/* .IP "\fB-R pathname
+/* Replace the message body by the content of the specified file.
+/* .IP "\fB-v\fR"
+/* Make the program more verbose.
+/* 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
+/*--*/
+
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
+#ifdef SMFIR_REPLBODY
+static char *body_file;
+
+#endif
+
static int test_reply(SMFICTX *ctx, int code)
{
(void) fflush(stdout); /* In case output redirected. */
if (code == SMFIR_REPLYCODE) {
- if (smfi_setreply(ctx, reply_code, reply_dsn, reply_message) != MI_SUCCESS)
+ if (smfi_setreply(ctx, reply_code, reply_dsn, reply_message) == MI_FAILURE)
fprintf(stderr, "smfi_setreply failed\n");
return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT);
} else {
#ifdef SMFIR_CHGHEADER
if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
fprintf(stderr, "smfi_chgheader failed");
+#endif
+#ifdef SMFIR_REPLBODY
+ if (body_file) {
+ char buf[BUFSIZ + 2];
+ FILE *fp;
+ size_t len;
+ int count;
+
+ if ((fp = fopen(body_file, "r")) == 0) {
+ perror(body_file);
+ } else {
+ printf("replace body with content of %s\n", body_file);
+ for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
+ len = strcspn(buf, "\n");
+ buf[len+0] = '\r';
+ buf[len+1] = '\n';
+ if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
+ fprintf(stderr, "body replace failure\n");
+ exit(1);
+ }
+ if (verbose)
+ printf("%.*s\n", (int) len, buf);
+ }
+ if (count == 0)
+ perror("fgets");
+ (void) fclose(fp);
+ }
+ }
#endif
return (test_reply(ctx, test_eom_reply));
}
{
"test-milter",
SMFI_VERSION,
- SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS,
+ SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS | SMFIF_CHGBODY,
test_connect,
test_helo,
test_mail,
int ch;
int code;
- while ((ch = getopt(argc, argv, "a:c:d:i:p:r:vC:")) > 0) {
+ while ((ch = getopt(argc, argv, "a:c:C:d:i:p:r:R:v")) > 0) {
switch (ch) {
case 'a':
action = optarg;
case 'C':
conn_count = atoi(optarg);
break;
+#ifdef SMFIR_REPLBODY
+ case 'R':
+ if (body_file) {
+ fprintf(stderr, "too many -R options\n");
+ exit(1);
+ }
+ body_file = optarg;
+#endif
+ break;
default:
fprintf(stderr,
"usage: %s [-dv] \n"
"\t-p port milter application\n"
"\t[-r 'index label value'] replace header\n"
"\t[-C conn_count] when to exit\n",
+ "\t[-R body_text] replace body\n",
argv[0]);
exit(1);
}
char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
char *redirect_addr; /* info@spammer.tld */
- long data_size; /* message content size */
+ long data_size; /* data segment size */
+ long cont_length; /* message content length */
long rcpt_offset; /* more recipients here */
char *client_name; /* client hostname */
char *client_addr; /* client address */
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->cont_length,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
message->inspect_xport = 0;
message->redirect_addr = 0;
message->data_size = 0;
+ message->cont_length = 0;
message->warn_offset = 0;
message->warn_time = 0;
message->rcpt_offset = 0;
continue;
if (rec_type == REC_TYPE_SIZE) {
if (message->data_offset == 0) {
- if ((count = sscanf(start, "%ld %ld %d %d",
+ if ((count = sscanf(start, "%ld %ld %d %d %ld",
&message->data_size, &message->data_offset,
- &nrcpt, &message->rflags)) >= 3) {
+ &nrcpt, &message->rflags,
+ &message->cont_length)) >= 3) {
/* Postfix >= 1.0 (a.k.a. 20010228). */
if (message->data_offset <= 0 || message->data_size <= 0) {
msg_warn("%s: invalid size record: %.100s",
break;
}
}
+ /* Postfix < 2.4 compatibility. */
+ if (message->cont_length == 0) {
+ message->cont_length = message->data_size;
+ } else if (message->cont_length < 0) {
+ msg_warn("%s: invalid size record: %.100s",
+ message->queue_id, start);
+ rec_type = REC_TYPE_ERROR;
+ break;
+ }
continue;
}
if (rec_type == REC_TYPE_TIME) {
if (message->sender == 0) {
message->sender = mystrdup(start);
opened(message->queue_id, message->sender,
- message->data_size, nrcpt,
+ message->cont_length, nrcpt,
"queue %s", message->queue_name);
}
continue;
int rcpt_per_stack; /* extra slots reserved for jobs put
* on the job stack */
int rcpt_unused; /* available in-core recipient slots */
- int refill_limit; /* recipient batch size for message refill */
+ int refill_limit; /* recipient batch size for message
+ * refill */
int refill_delay; /* delay before message refill */
int slot_cost; /* cost of new preemption slot (# of
* selected entries) */
struct timeval active_time; /* time of entry into active queue */
time_t queued_time; /* sanitized time when moved to the
* active queue */
- time_t refill_time; /* sanitized time of last message refill */
+ time_t refill_time; /* sanitized time of last message
+ * refill */
long warn_offset; /* warning bounce flag offset */
time_t warn_time; /* time next warning to be sent */
long data_offset; /* data seek offset */
char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
char *redirect_addr; /* info@spammer.tld */
- long data_size; /* message content size */
+ long data_size; /* data segment size */
+ long cont_length; /* message content length */
long rcpt_offset; /* more recipients here */
char *client_name; /* client hostname */
char *client_addr; /* client address */
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->cont_length,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
message->inspect_xport = 0;
message->redirect_addr = 0;
message->data_size = 0;
+ message->cont_length = 0;
message->warn_offset = 0;
message->warn_time = 0;
message->rcpt_offset = 0;
continue;
if (rec_type == REC_TYPE_SIZE) {
if (message->data_offset == 0) {
- if ((count = sscanf(start, "%ld %ld %d %d",
+ if ((count = sscanf(start, "%ld %ld %d %d %ld",
&message->data_size, &message->data_offset,
- &message->rcpt_unread, &message->rflags)) >= 3) {
+ &message->rcpt_unread, &message->rflags,
+ &message->cont_length)) >= 3) {
/* Postfix >= 1.0 (a.k.a. 20010228). */
if (message->data_offset <= 0 || message->data_size <= 0) {
msg_warn("%s: invalid size record: %.100s",
break;
}
}
+ /* Postfix < 2.4 compatibility. */
+ if (message->cont_length == 0) {
+ message->cont_length = message->data_size;
+ } else if (message->cont_length < 0) {
+ msg_warn("%s: invalid size record: %.100s",
+ message->queue_id, start);
+ rec_type = REC_TYPE_ERROR;
+ break;
+ }
continue;
}
if (rec_type == REC_TYPE_TIME) {
if (message->sender == 0) {
message->sender = mystrdup(start);
opened(message->queue_id, message->sender,
- message->data_size, message->rcpt_unread,
+ message->cont_length, message->rcpt_unread,
"queue %s", message->queue_name);
}
continue;
>>> mail sname@sdomain
OK
>>> rcpt rname@rdomain
-./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<example.tld>
-554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld
+./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<example.tld>
+554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain
>>> #
>>> # Check MX access
>>> #