From: Wietse Venema Date: Tue, 16 Jan 2007 05:00:00 +0000 (-0500) Subject: postfix-2.4-20070116 X-Git-Tag: v2.4.0-RC1~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5060b869c282ca23921a9cc0b49d9e4803d58264;p=thirdparty%2Fpostfix.git postfix-2.4-20070116 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 2970847d7..c45e2f9ce 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -28,6 +28,7 @@ -TBOUNCE_TIME_PARAMETER -TCFG_PARSER -TCIDR_MATCH +-TCLEANUP_BODY_REGION -TCLEANUP_STATE -TCLEANUP_STAT_DETAIL -TCLIENT_LIST diff --git a/postfix/HISTORY b/postfix/HISTORY index f72f6cc80..0e6d4be2a 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -13096,16 +13096,25 @@ Apologies for any names omitted. 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: diff --git a/postfix/README_FILES/MILTER_README b/postfix/README_FILES/MILTER_README index ca95394f6..ac96f8c88 100644 --- a/postfix/README_FILES/MILTER_README +++ b/postfix/README_FILES/MILTER_README @@ -15,9 +15,10 @@ authenticity (examples: SenderID+SPF and Domain keys) or to digitally sign mail (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: @@ -513,7 +514,7 @@ the CONTENT_INSPECTION_README document for a discussion. 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 diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 84d03ca59..0173df6be 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -17,6 +17,21 @@ Incompatibility with Postfix 2.2 and earlier 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 =================================================== diff --git a/postfix/html/MILTER_README.html b/postfix/html/MILTER_README.html index 2619bab66..1bbb5cce0 100644 --- a/postfix/html/MILTER_README.html +++ b/postfix/html/MILTER_README.html @@ -35,8 +35,10 @@ href="http://sourceforge.net/projects/dk-milter/">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. +

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.

@@ -793,8 +795,8 @@ operation will log a warning like this:

-

The solution is (to wait for) a Postfix version that supports -the missing functionality. +

The solution is to use a Postfix version that supports the +missing functionality.

  • Most Milter configuration options are global. Future Postfix versions may support per-Milter timeouts, per-Milter error handling, diff --git a/postfix/proto/MILTER_README.html b/postfix/proto/MILTER_README.html index 3fcf83da2..853bb8ae3 100644 --- a/postfix/proto/MILTER_README.html +++ b/postfix/proto/MILTER_README.html @@ -35,8 +35,10 @@ href="http://sourceforge.net/projects/dk-milter/">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. +

    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.

    @@ -793,8 +795,8 @@ operation will log a warning like this:

    -

    The solution is (to wait for) a Postfix version that supports -the missing functionality. +

    The solution is to use a Postfix version that supports the +missing functionality.

  • Most Milter configuration options are global. Future Postfix versions may support per-Milter timeouts, per-Milter error handling, diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index 2bf737122..563023324 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -3,12 +3,14 @@ SRCS = cleanup.c cleanup_out.c cleanup_envelope.c cleanup_message.c \ 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) @@ -59,15 +61,20 @@ cleanup_masquerade: cleanup_masquerade.o 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: @@ -176,6 +183,7 @@ cleanup_milter_test6a: cleanup_milter test-queue-file6 cleanup_milter.in6a \ ./cleanup_milter /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 @@ -184,6 +192,7 @@ cleanup_milter_test6b: cleanup_milter test-queue-file6 cleanup_milter.in6b \ ./cleanup_milter /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 @@ -192,6 +201,7 @@ cleanup_milter_test6c: cleanup_milter test-queue-file6 cleanup_milter.in6c \ ./cleanup_milter /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 @@ -200,6 +210,7 @@ cleanup_milter_test7: cleanup_milter test-queue-file7 cleanup_milter.in7 \ ./cleanup_milter /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 @@ -208,6 +219,7 @@ cleanup_milter_test8: cleanup_milter test-queue-file8 cleanup_milter.in8 \ ./cleanup_milter /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 @@ -216,6 +228,52 @@ cleanup_milter_test9: cleanup_milter test-queue-file9 cleanup_milter.in9 \ ./cleanup_milter /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 /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 /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 /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 /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 /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; \ @@ -322,6 +380,7 @@ cleanup_api.o: ../../include/msg.h 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 @@ -332,6 +391,33 @@ cleanup_api.o: ../../include/vstream.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 @@ -447,6 +533,7 @@ cleanup_extracted.o: cleanup.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 @@ -536,6 +623,7 @@ cleanup_map1n.o: cleanup.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 @@ -716,6 +804,7 @@ cleanup_out_recipient.o: cleanup_out_recipient.c 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 @@ -746,6 +835,7 @@ cleanup_rewrite.o: cleanup_rewrite.c 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 diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index 2c7637ecb..e31301f37 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -31,6 +31,7 @@ #include #include #include +#include /* * Milter library. @@ -69,6 +70,7 @@ typedef struct CLEANUP_STATE { 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 */ @@ -89,6 +91,10 @@ typedef struct CLEANUP_STATE { #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 */ @@ -97,6 +103,13 @@ typedef struct CLEANUP_STATE { 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; /* @@ -281,6 +294,20 @@ extern void cleanup_milter_emul_data(CLEANUP_STATE *, MILTERS *); (((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 diff --git a/postfix/src/cleanup/cleanup_api.c b/postfix/src/cleanup/cleanup_api.c index 4769289b8..c06627436 100644 --- a/postfix/src/cleanup/cleanup_api.c +++ b/postfix/src/cleanup/cleanup_api.c @@ -111,6 +111,7 @@ #include #include #include +#include /* Milter library. */ @@ -198,6 +199,7 @@ void cleanup_control(CLEANUP_STATE *state, int flags) int cleanup_flush(CLEANUP_STATE *state) { + const char *myname = "cleanup_flush"; int status; char *junk; VSTRING *trace_junk; @@ -234,6 +236,21 @@ int cleanup_flush(CLEANUP_STATE *state) } } + /* + * 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 diff --git a/postfix/src/cleanup/cleanup_body_region.c b/postfix/src/cleanup/cleanup_body_region.c new file mode 100644 index 000000000..7ad47b05c --- /dev/null +++ b/postfix/src/cleanup/cleanup_body_region.c @@ -0,0 +1,266 @@ +/*++ +/* 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 + +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ + +#include + +#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); +} diff --git a/postfix/src/cleanup/cleanup_envelope.c b/postfix/src/cleanup/cleanup_envelope.c index eb4171bdf..ef4dbc7dc 100644 --- a/postfix/src/cleanup/cleanup_envelope.c +++ b/postfix/src/cleanup/cleanup_envelope.c @@ -89,10 +89,11 @@ void cleanup_envelope(CLEANUP_STATE *state, int type, * 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. diff --git a/postfix/src/cleanup/cleanup_extracted.c b/postfix/src/cleanup/cleanup_extracted.c index 60f0ab345..5f02e2585 100644 --- a/postfix/src/cleanup/cleanup_extracted.c +++ b/postfix/src/cleanup/cleanup_extracted.c @@ -316,16 +316,4 @@ void cleanup_extracted_finish(CLEANUP_STATE *state) } 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); } diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 5e71c8b89..e777f455a 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -831,6 +831,7 @@ static void cleanup_message_headerbody(CLEANUP_STATE *state, int type, 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; } diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c index da4fddb1f..348b3b790 100644 --- a/postfix/src/cleanup/cleanup_milter.c +++ b/postfix/src/cleanup/cleanup_milter.c @@ -1254,15 +1254,35 @@ static const char *cleanup_del_rcpt(void *context, char *ext_rcpt) /* 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 */ @@ -1779,6 +1799,12 @@ static void open_queue_file(CLEANUP_STATE *state, const char *path) } } } + 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, @@ -1819,7 +1845,7 @@ int main(int unused_argc, char **argv) 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); @@ -1903,6 +1929,25 @@ int main(int unused_argc, char **argv) } 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]); } diff --git a/postfix/src/cleanup/cleanup_milter.in10a b/postfix/src/cleanup/cleanup_milter.in10a new file mode 100644 index 000000000..997b8a7a6 --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.in10a @@ -0,0 +1,11 @@ +# +# 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 diff --git a/postfix/src/cleanup/cleanup_milter.in10b b/postfix/src/cleanup/cleanup_milter.in10b new file mode 100644 index 000000000..ba3b07f36 --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.in10b @@ -0,0 +1,12 @@ +# +# 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 diff --git a/postfix/src/cleanup/cleanup_milter.in10c b/postfix/src/cleanup/cleanup_milter.in10c new file mode 100644 index 000000000..79af0ce14 --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.in10c @@ -0,0 +1,14 @@ +# +# 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 diff --git a/postfix/src/cleanup/cleanup_milter.in10d b/postfix/src/cleanup/cleanup_milter.in10d new file mode 100644 index 000000000..b7c515a8f --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.in10d @@ -0,0 +1,14 @@ +# +# 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 diff --git a/postfix/src/cleanup/cleanup_milter.in10e b/postfix/src/cleanup/cleanup_milter.in10e new file mode 100644 index 000000000..763f79b3b --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.in10e @@ -0,0 +1,13 @@ +# +# 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 diff --git a/postfix/src/cleanup/cleanup_milter.ref10a b/postfix/src/cleanup/cleanup_milter.ref10a new file mode 100644 index 000000000..38c5c84fb --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.ref10a @@ -0,0 +1,52 @@ +*** 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 + 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 1434 regular_text: pariatur? + 1446 regular_text: + 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 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 *** diff --git a/postfix/src/cleanup/cleanup_milter.ref10b b/postfix/src/cleanup/cleanup_milter.ref10b new file mode 100644 index 000000000..38c5c84fb --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.ref10b @@ -0,0 +1,52 @@ +*** 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 + 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 1434 regular_text: pariatur? + 1446 regular_text: + 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 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 *** diff --git a/postfix/src/cleanup/cleanup_milter.ref10c b/postfix/src/cleanup/cleanup_milter.ref10c new file mode 100644 index 000000000..78704f2fc --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.ref10c @@ -0,0 +1,82 @@ +*** 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 + 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 1434 regular_text: pariatur? + 1446 regular_text: + 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 2320 pointer_record: 2337 + 2337 regular_text: + 2340 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem + 2405 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 2472 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 2540 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 2609 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 2678 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 2744 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 2812 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 2879 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 2944 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 3018 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 3087 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 3155 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 3222 regular_text: pariatur? + 3234 regular_text: + 3237 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 3302 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 3367 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 3435 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 3502 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 3573 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 3640 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 3707 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 3776 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 3846 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 3912 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 3981 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 4047 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 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 *** diff --git a/postfix/src/cleanup/cleanup_milter.ref10d b/postfix/src/cleanup/cleanup_milter.ref10d new file mode 100644 index 000000000..38c5c84fb --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.ref10d @@ -0,0 +1,52 @@ +*** 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 + 617 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 684 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 752 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 821 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 890 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 956 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 1024 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 1091 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 1156 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 1230 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 1299 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 1367 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 1434 regular_text: pariatur? + 1446 regular_text: + 1449 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 1514 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 1579 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 1647 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 1714 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 1785 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 1852 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 1919 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 1988 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 2058 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 2124 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 2193 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 2259 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 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 *** diff --git a/postfix/src/cleanup/cleanup_milter.ref10e b/postfix/src/cleanup/cleanup_milter.ref10e new file mode 100644 index 000000000..81b05025d --- /dev/null +++ b/postfix/src/cleanup/cleanup_milter.ref10e @@ -0,0 +1,86 @@ +*** 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 + 648 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 715 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 783 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 852 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 921 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 987 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 1055 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 1122 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 1187 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 1261 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 1330 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 1398 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 1465 regular_text: pariatur? + 1477 regular_text: + 1480 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 1545 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 1610 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 1678 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 1745 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 1816 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 1883 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 1950 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 2019 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 2089 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 2155 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 2224 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 2290 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 2351 pointer_record: 2399 + 2399 regular_text: + 2402 regular_text: Sed ut perspiciatis unde omnis iste natus error sit voluptatem + 2467 regular_text: accusantium doloremque laudantium, totam rem aperiam, eaque ipsa + 2534 regular_text: quae ab illo inventore veritatis et quasi architecto beatae vitae + 2602 regular_text: dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit + 2671 regular_text: aspernatur aut odit aut fugit, sed quia consequuntur magni dolores + 2740 regular_text: eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam + 2806 regular_text: est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci + 2874 regular_text: velit, sed quia non numquam eius modi tempora incidunt ut labore + 2941 regular_text: et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima + 3006 regular_text: veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, + 3080 regular_text: nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure + 3149 regular_text: reprehenderit qui in ea voluptate velit esse quam nihil molestiae + 3217 regular_text: consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla + 3284 regular_text: pariatur? + 3296 regular_text: + 3299 regular_text: At vero eos et accusamus et iusto odio dignissimos ducimus qui + 3364 regular_text: blanditiis praesentium voluptatum deleniti atque corrupti quos + 3429 regular_text: dolores et quas molestias excepturi sint occaecati cupiditate non + 3497 regular_text: provident, similique sunt in culpa qui officia deserunt mollitia + 3564 regular_text: animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis + 3635 regular_text: est et expedita distinctio. Nam libero tempore, cum soluta nobis + 3702 regular_text: est eligendi optio cumque nihil impedit quo minus id quod maxime + 3769 regular_text: placeat facere possimus, omnis voluptas assumenda est, omnis dolor + 3838 regular_text: repellendus. Temporibus autem quibusdam et aut officiis debitis aut + 3908 regular_text: rerum necessitatibus saepe eveniet ut et voluptates repudiandae + 3974 regular_text: sint et molestiae non recusandae. Itaque earum rerum hic tenetur a + 4043 regular_text: sapiente delectus, ut aut reiciendis voluptatibus maiores alias + 4109 regular_text: consequatur aut perferendis doloribus asperiores repellat. + 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 *** diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c index 9a35f107d..e07bd2ace 100644 --- a/postfix/src/cleanup/cleanup_state.c +++ b/postfix/src/cleanup/cleanup_state.c @@ -89,6 +89,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) 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; @@ -115,6 +116,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) state->client_port = 0; state->milter_ext_from = 0; state->milter_ext_rcpt = 0; + state->body_regions = state->curr_body_region = 0; return (state); } @@ -165,5 +167,7 @@ void cleanup_state_free(CLEANUP_STATE *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); } diff --git a/postfix/src/cleanup/loremipsum b/postfix/src/cleanup/loremipsum new file mode 100644 index 000000000..774f86deb --- /dev/null +++ b/postfix/src/cleanup/loremipsum @@ -0,0 +1,28 @@ +Sed ut perspiciatis unde omnis iste natus error sit voluptatem +accusantium doloremque laudantium, totam rem aperiam, eaque ipsa +quae ab illo inventore veritatis et quasi architecto beatae vitae +dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit +aspernatur aut odit aut fugit, sed quia consequuntur magni dolores +eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam +est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci +velit, sed quia non numquam eius modi tempora incidunt ut labore +et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima +veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, +nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure +reprehenderit qui in ea voluptate velit esse quam nihil molestiae +consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla +pariatur? + +At vero eos et accusamus et iusto odio dignissimos ducimus qui +blanditiis praesentium voluptatum deleniti atque corrupti quos +dolores et quas molestias excepturi sint occaecati cupiditate non +provident, similique sunt in culpa qui officia deserunt mollitia +animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis +est et expedita distinctio. Nam libero tempore, cum soluta nobis +est eligendi optio cumque nihil impedit quo minus id quod maxime +placeat facere possimus, omnis voluptas assumenda est, omnis dolor +repellendus. Temporibus autem quibusdam et aut officiis debitis aut +rerum necessitatibus saepe eveniet ut et voluptates repudiandae +sint et molestiae non recusandae. Itaque earum rerum hic tenetur a +sapiente delectus, ut aut reiciendis voluptatibus maiores alias +consequatur aut perferendis doloribus asperiores repellat. diff --git a/postfix/src/cleanup/loremipsum2 b/postfix/src/cleanup/loremipsum2 new file mode 100644 index 000000000..93cfa6796 --- /dev/null +++ b/postfix/src/cleanup/loremipsum2 @@ -0,0 +1,57 @@ +Sed ut perspiciatis unde omnis iste natus error sit voluptatem +accusantium doloremque laudantium, totam rem aperiam, eaque ipsa +quae ab illo inventore veritatis et quasi architecto beatae vitae +dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit +aspernatur aut odit aut fugit, sed quia consequuntur magni dolores +eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam +est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci +velit, sed quia non numquam eius modi tempora incidunt ut labore +et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima +veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, +nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure +reprehenderit qui in ea voluptate velit esse quam nihil molestiae +consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla +pariatur? + +At vero eos et accusamus et iusto odio dignissimos ducimus qui +blanditiis praesentium voluptatum deleniti atque corrupti quos +dolores et quas molestias excepturi sint occaecati cupiditate non +provident, similique sunt in culpa qui officia deserunt mollitia +animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis +est et expedita distinctio. Nam libero tempore, cum soluta nobis +est eligendi optio cumque nihil impedit quo minus id quod maxime +placeat facere possimus, omnis voluptas assumenda est, omnis dolor +repellendus. Temporibus autem quibusdam et aut officiis debitis aut +rerum necessitatibus saepe eveniet ut et voluptates repudiandae +sint et molestiae non recusandae. Itaque earum rerum hic tenetur a +sapiente delectus, ut aut reiciendis voluptatibus maiores alias +consequatur aut perferendis doloribus asperiores repellat. + +Sed ut perspiciatis unde omnis iste natus error sit voluptatem +accusantium doloremque laudantium, totam rem aperiam, eaque ipsa +quae ab illo inventore veritatis et quasi architecto beatae vitae +dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit +aspernatur aut odit aut fugit, sed quia consequuntur magni dolores +eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam +est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci +velit, sed quia non numquam eius modi tempora incidunt ut labore +et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima +veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, +nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure +reprehenderit qui in ea voluptate velit esse quam nihil molestiae +consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla +pariatur? + +At vero eos et accusamus et iusto odio dignissimos ducimus qui +blanditiis praesentium voluptatum deleniti atque corrupti quos +dolores et quas molestias excepturi sint occaecati cupiditate non +provident, similique sunt in culpa qui officia deserunt mollitia +animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis +est et expedita distinctio. Nam libero tempore, cum soluta nobis +est eligendi optio cumque nihil impedit quo minus id quod maxime +placeat facere possimus, omnis voluptas assumenda est, omnis dolor +repellendus. Temporibus autem quibusdam et aut officiis debitis aut +rerum necessitatibus saepe eveniet ut et voluptates repudiandae +sint et molestiae non recusandae. Itaque earum rerum hic tenetur a +sapiente delectus, ut aut reiciendis voluptatibus maiores alias +consequatur aut perferendis doloribus asperiores repellat. diff --git a/postfix/src/cleanup/test-queue-file10 b/postfix/src/cleanup/test-queue-file10 new file mode 100644 index 000000000..f5a7b0194 Binary files /dev/null and b/postfix/src/cleanup/test-queue-file10 differ diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index f3097f91a..49e288d89 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -273,7 +273,7 @@ tests: tok822_test mime_tests strip_addr_test tok822_limit_test \ 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 @@ -337,6 +337,11 @@ mime_garb3: mime_state mime_garb3.in mime_garb3.ref 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_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.tmp diff tok822_limit.ref tok822_limit.tmp diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 1bce4ac68..4dac78e6c 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * 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 diff --git a/postfix/src/global/mime_garb3.ref b/postfix/src/global/mime_garb3.ref index 873ef91fa..ee8ef36b8 100644 --- a/postfix/src/global/mime_garb3.ref +++ b/postfix/src/global/mime_garb3.ref @@ -9,7 +9,7 @@ MAIN 95 |Content-Type: Multipart/Mixed; 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 diff --git a/postfix/src/global/mime_garb4.in b/postfix/src/global/mime_garb4.in new file mode 100644 index 000000000..16dcfc64e --- /dev/null +++ b/postfix/src/global/mime_garb4.in @@ -0,0 +1,34 @@ +From: Some One +To: Some One +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 +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 diff --git a/postfix/src/global/mime_garb4.ref b/postfix/src/global/mime_garb4.ref new file mode 100644 index 000000000..bd0e5ccda --- /dev/null +++ b/postfix/src/global/mime_garb4.ref @@ -0,0 +1,50 @@ +MAIN 0 |From: Some One +MAIN 32 |To: Some One +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 +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 diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c index b81fc1f90..4b4bf69f9 100644 --- a/postfix/src/global/mime_state.c +++ b/postfix/src/global/mime_state.c @@ -499,6 +499,7 @@ MIME_STATE *mime_state_alloc(int flags, /* 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); @@ -938,6 +939,15 @@ int mime_state_update(MIME_STATE *state, int rec_type, * 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. * @@ -973,13 +983,14 @@ int mime_state_update(MIME_STATE *state, int rec_type, * 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 { @@ -989,9 +1000,25 @@ int mime_state_update(MIME_STATE *state, int rec_type, 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; + } } } diff --git a/postfix/src/global/rec_type.h b/postfix/src/global/rec_type.h index bf158f934..cd0873f9e 100644 --- a/postfix/src/global/rec_type.h +++ b/postfix/src/global/rec_type.h @@ -121,11 +121,12 @@ * * 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 diff --git a/postfix/src/global/record.c b/postfix/src/global/record.c index 3ef7ca7b5..12dbac4ba 100644 --- a/postfix/src/global/record.c +++ b/postfix/src/global/record.c @@ -52,6 +52,10 @@ /* 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 @@ -102,6 +106,10 @@ /* 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. diff --git a/postfix/src/global/record.h b/postfix/src/global/record.h index 6e75734a3..a5e8b8ced 100644 --- a/postfix/src/global/record.h +++ b/postfix/src/global/record.h @@ -41,7 +41,7 @@ extern int rec_goto(VSTREAM *, const char *); #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 */ @@ -52,6 +52,13 @@ extern int rec_goto(VSTREAM *, const char *); #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 */ diff --git a/postfix/src/milter/milter.c b/postfix/src/milter/milter.c index f006ffc71..51f968d80 100644 --- a/postfix/src/milter/milter.c +++ b/postfix/src/milter/milter.c @@ -280,7 +280,7 @@ void milter_edit_callback(MILTERS *milters, 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; diff --git a/postfix/src/milter/milter.h b/postfix/src/milter/milter.h index 9e480193a..676322d4a 100644 --- a/postfix/src/milter/milter.h +++ b/postfix/src/milter/milter.h @@ -67,7 +67,7 @@ typedef struct MILTERS { 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 *); @@ -75,7 +75,7 @@ typedef const char *(*MILTER_ADD_HEADER_FN) (void *, char *, char *); 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 *, @@ -103,6 +103,13 @@ extern int milter_send(MILTERS *, VSTREAM *); 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 {}. */ diff --git a/postfix/src/milter/milter8.c b/postfix/src/milter/milter8.c index 96f637b49..2ccd7e749 100644 --- a/postfix/src/milter/milter8.c +++ b/postfix/src/milter/milter8.c @@ -196,6 +196,7 @@ /* Global library. */ +#include /* var_line_limit */ #include #include #include @@ -866,9 +867,12 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 @@ -970,17 +974,30 @@ static const char *milter8_event(MILTER8 *milter, int event, /* * 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 ? @@ -1001,7 +1018,7 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 @@ -1021,7 +1038,7 @@ static const char *milter8_event(MILTER8 *milter, int event, /* 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 @@ -1036,11 +1053,11 @@ static const char *milter8_event(MILTER8 *milter, int event, 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"); } /* @@ -1055,9 +1072,9 @@ static const char *milter8_event(MILTER8 *milter, int event, 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"); } /* @@ -1072,10 +1089,10 @@ static const char *milter8_event(MILTER8 *milter, int event, 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"); } /* @@ -1090,7 +1107,7 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 /* @@ -1107,7 +1124,7 @@ static const char *milter8_event(MILTER8 *milter, int event, 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]) @@ -1116,7 +1133,7 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 (;;) { @@ -1132,9 +1149,9 @@ static const char *milter8_event(MILTER8 *milter, int event, 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)); } /* @@ -1148,8 +1165,8 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 /* @@ -1170,8 +1187,7 @@ static const char *milter8_event(MILTER8 *milter, int event, 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; @@ -1179,13 +1195,13 @@ static const char *milter8_event(MILTER8 *milter, int event, 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, @@ -1197,7 +1213,7 @@ static const char *milter8_event(MILTER8 *milter, int event, (ssize_t) index, STR(milter->buf)); if (edit_resp) - return (edit_resp); + MILTER8_EVENT_BREAK(edit_resp); continue; #endif @@ -1209,13 +1225,12 @@ static const char *milter8_event(MILTER8 *milter, int event, 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; /* @@ -1231,20 +1246,19 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 @@ -1255,12 +1269,11 @@ static const char *milter8_event(MILTER8 *milter, int event, 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; /* @@ -1270,31 +1283,47 @@ static const char *milter8_event(MILTER8 *milter, int event, 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", @@ -1304,7 +1333,7 @@ static const char *milter8_event(MILTER8 *milter, int event, (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); } /* @@ -1315,8 +1344,40 @@ static const char *milter8_event(MILTER8 *milter, int event, 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 */ @@ -1332,7 +1393,7 @@ static void milter8_connect(MILTER8 *milter) 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 @@ -1651,6 +1712,7 @@ static const char *milter8_helo_event(MILTER *m, const char *helo_name, 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); diff --git a/postfix/src/milter/test-milter.c b/postfix/src/milter/test-milter.c index ad76eb800..ba7289f66 100644 --- a/postfix/src/milter/test-milter.c +++ b/postfix/src/milter/test-milter.c @@ -1,34 +1,52 @@ - /* - * 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 #include #include @@ -110,12 +128,17 @@ static char *chg_val; #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 { @@ -227,6 +250,34 @@ static sfsistat test_eom(SMFICTX *ctx) #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)); } @@ -271,7 +322,7 @@ static struct smfiDesc smfilter = { "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, @@ -314,7 +365,7 @@ int main(int argc, char **argv) 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; @@ -364,6 +415,15 @@ int main(int argc, char **argv) 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" @@ -373,6 +433,7 @@ int main(int argc, char **argv) "\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); } diff --git a/postfix/src/oqmgr/qmgr.h b/postfix/src/oqmgr/qmgr.h index 73744c5d8..20f8c3a18 100644 --- a/postfix/src/oqmgr/qmgr.h +++ b/postfix/src/oqmgr/qmgr.h @@ -230,7 +230,8 @@ struct QMGR_MESSAGE { 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 */ diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c index 8d3b682ab..7e06b5dc5 100644 --- a/postfix/src/oqmgr/qmgr_deliver.c +++ b/postfix/src/oqmgr/qmgr_deliver.c @@ -158,7 +158,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) 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, diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index 8e56e56e4..a646daef9 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -172,6 +172,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, 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; @@ -506,9 +507,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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", @@ -533,6 +535,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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) { @@ -567,7 +578,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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; diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 5582ef81a..f4b354602 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -139,7 +139,8 @@ struct QMGR_TRANSPORT { 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) */ @@ -259,7 +260,8 @@ struct QMGR_MESSAGE { 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 */ @@ -273,7 +275,8 @@ struct QMGR_MESSAGE { 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 */ diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index c0589e16d..2785e59a9 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -163,7 +163,7 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) 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, diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index ae0dd174d..9be26ec1c 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -183,6 +183,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, 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; @@ -547,9 +548,10 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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", @@ -574,6 +576,15 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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) { @@ -608,7 +619,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message) 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; diff --git a/postfix/src/smtpd/smtpd_exp.ref b/postfix/src/smtpd/smtpd_exp.ref index 75b6c84f3..c04381ba8 100644 --- a/postfix/src/smtpd/smtpd_exp.ref +++ b/postfix/src/smtpd/smtpd_exp.ref @@ -107,8 +107,8 @@ OK >>> mail sname@sdomain OK >>> rcpt rname@rdomain -./smtpd_check: : 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= to= proto=SMTP helo= -554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@example.tld +./smtpd_check: : 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= to= proto=SMTP helo= +554 5.7.1 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain >>> # >>> # Check MX access >>> #