Subject: Postfix 19991231 Patchlevel 08 available

From: [email-masked] (Wietse Venema)
Date: Sun, 28 May 2000 22:22:10 -0400 (EDT)

This patch provides an emergency band-aid for the next wave of
MicroSoft email worms, fixes one bug, and makes external content
filtering a bit more robust.

  - Feature: specify "body_checks = regexp:/etc/postfix/body_checks"
    for an emergency content filter that looks at non-header lines
    one line at a time (including MIME headers inside the message
    body).  This feature uses the same syntax as the header_checks
    patterns.  Details in conf/sample-filter.cf. 

    This feature is also available in Postfix snapshot 20000528.

  - Bugfix: the masquerade_exceptions feature was case sensitive.

  - Robustness: upon receipt of mail, Postfix maps MAILER-DAEMON@myorigin
    sender address back into the magic null string, which prevents
    mail from looping after processing by an external content filter.

A fully-patched version of the source code is being made available
via the usual FTP servers, primary site:

    ftp://ftp.porcupine.org/mirrors/postfix-release/official/

Files: postfix-19991231-pl08.tar.gz and postfix-19991231-pl08.tar.gz.sig.

Or, if you use a web browser,

    ftp://ftp.porcupine.org/mirrors/postfix-release/index.html

Happy Postfixing.

	Wietse

Prereq: "Postfix-19991231-pl07"
diff -cr --new-file /tmp/postfix-19991231-pl07/global/mail_version.h ./global/mail_version.h
*** /tmp/postfix-19991231-pl07/global/mail_version.h	Thu Apr 13 14:47:12 2000
--- ./global/mail_version.h	Sun May 28 18:53:10 2000
***************
*** 15,21 ****
    * Version of this program.
    */
  #define VAR_MAIL_VERSION	"mail_version"
! #define DEF_MAIL_VERSION	"Postfix-19991231-pl07"
  extern char *var_mail_version;
  
  /* LICENSE
--- 15,21 ----
    * Version of this program.
    */
  #define VAR_MAIL_VERSION	"mail_version"
! #define DEF_MAIL_VERSION	"Postfix-19991231-pl08"
  extern char *var_mail_version;
  
  /* LICENSE
diff -cr --new-file /tmp/postfix-19991231-pl07/HISTORY ./HISTORY
*** /tmp/postfix-19991231-pl07/HISTORY	Thu May 11 20:40:06 2000
--- ./HISTORY	Sun May 28 18:50:49 2000
***************
*** 3713,3715 ****
--- 3713,3734 ----
  
  	Bugfix: Postfix would incorrectly reject domain names with
  	adjacent - characters. File: util/valid_hostname.c.
+ 
+ 20000520
+ 
+ 	Robustness: upon receipt of mail, map the mailer-daemon
+ 	sender address back into the magic null string. File:
+ 	cleanup/cleanup_envelope.c.
+ 
+ 20000524
+ 
+ 	Bugfix: the code for masquerade_exceptions was case sensitive.
+ 	Reported by Eduard Vopicka.  File: cleanup/cleanup_masquerade.c.
+ 
+ 20000528
+ 
+ 	Feature: specify "body_checks=regexp:/file/name" for a very
+ 	crude one line at a time message body content filter.  This
+ 	feature uses the same filtering syntax as the header_checks
+ 	feature.  File:  cleanup/cleanup_message.c. See also the
+ 	conf/sample-filter.cf file.
diff -cr --new-file /tmp/postfix-19991231-pl07/RELEASE_NOTES ./RELEASE_NOTES
*** /tmp/postfix-19991231-pl07/RELEASE_NOTES	Thu May 11 19:40:45 2000
--- ./RELEASE_NOTES	Sun May 28 19:43:08 2000
***************
*** 1,3 ****
--- 1,11 ----
+ Major changes with postfix-19991231-pl08:
+ =========================================
+ 
+ Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
+ and dirty emergency content filter that looks at non-header lines
+ one line at a time (including MIME headers inside the message body).
+ Details in conf/sample-filter.cf.
+ 
  Incompatible changes with postfix-19991231-pl07:
  ================================================
  
diff -cr --new-file /tmp/postfix-19991231-pl07/cleanup/cleanup.c ./cleanup/cleanup.c
*** /tmp/postfix-19991231-pl07/cleanup/cleanup.c	Thu Apr 13 13:39:10 2000
--- ./cleanup/cleanup.c	Sun May 28 19:00:34 2000
***************
*** 60,65 ****
--- 60,74 ----
  /*	this program. See the Postfix \fBmain.cf\fR file for syntax details
  /*	and for default values. Use the \fBpostfix reload\fR command after
  /*	a configuration change.
+ /* .SH Content filtering
+ /* .IP \fBbody_checks\fR
+ /*	Lookup tables with content filters for message body lines.
+ /*	These filters see physical lines one at a time, in chunks of
+ /*	at most line_length_limit bytes.
+ /* .IP \fBheader_checks\fR
+ /*	Lookup tables with content filters for message header lines.
+ /*	These filters see logical headers one at a time, including headers
+ /*	that span multiple lines.
  /* .SH Miscellaneous
  /* .ad
  /* .fi
***************
*** 175,180 ****
--- 184,190 ----
  char   *var_masq_domains;		/* masquerade domains */
  char   *var_masq_exceptions;		/* users not masqueraded */
  char   *var_header_checks;		/* any header checks */
+ char   *var_body_checks;		/* any body checks */
  int     var_dup_filter_limit;		/* recipient dup filter */
  char   *var_empty_addr;			/* destination of bounced bounces */
  int     var_delay_warn_time;		/* delay that triggers warning */
***************
*** 189,194 ****
--- 199,205 ----
  MAPS   *cleanup_send_canon_maps;
  MAPS   *cleanup_rcpt_canon_maps;
  MAPS   *cleanup_header_checks;
+ MAPS   *cleanup_body_checks;
  MAPS   *cleanup_virtual_maps;
  ARGV   *cleanup_masq_domains;
  
***************
*** 420,425 ****
--- 431,439 ----
      if (*var_header_checks)
  	cleanup_header_checks =
  	    maps_create(VAR_HEADER_CHECKS, var_header_checks, DICT_FLAG_LOCK);
+     if (*var_body_checks)
+ 	cleanup_body_checks =
+ 	    maps_create(VAR_BODY_CHECKS, var_body_checks, DICT_FLAG_LOCK);
  }
  
  /* pre_accept - see if tables have changed */
***************
*** 473,478 ****
--- 487,493 ----
  	VAR_EMPTY_ADDR, DEF_EMPTY_ADDR, &var_empty_addr, 1, 0,
  	VAR_MASQ_EXCEPTIONS, DEF_MASQ_EXCEPTIONS, &var_masq_exceptions, 0, 0,
  	VAR_HEADER_CHECKS, DEF_HEADER_CHECKS, &var_header_checks, 0, 0,
+ 	VAR_BODY_CHECKS, DEF_BODY_CHECKS, &var_body_checks, 0, 0,
  	VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
  	VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
  	VAR_RCPT_WITHELD, DEF_RCPT_WITHELD, &var_rcpt_witheld, 1, 0,
diff -cr --new-file /tmp/postfix-19991231-pl07/cleanup/cleanup.h ./cleanup/cleanup.h
*** /tmp/postfix-19991231-pl07/cleanup/cleanup.h	Sat May  8 19:18:44 1999
--- ./cleanup/cleanup.h	Sun May 28 20:50:09 2000
***************
*** 62,67 ****
--- 62,68 ----
  extern MAPS *cleanup_send_canon_maps;
  extern MAPS *cleanup_rcpt_canon_maps;
  extern MAPS *cleanup_header_checks;
+ extern MAPS *cleanup_body_checks;
  extern MAPS *cleanup_virtual_maps;
  extern ARGV *cleanup_masq_domains;
  
diff -cr --new-file /tmp/postfix-19991231-pl07/cleanup/cleanup_envelope.c ./cleanup/cleanup_envelope.c
*** /tmp/postfix-19991231-pl07/cleanup/cleanup_envelope.c	Wed Jun 23 21:40:37 1999
--- ./cleanup/cleanup_envelope.c	Sat May 20 13:00:01 2000
***************
*** 30,35 ****
--- 30,39 ----
  #include <string.h>
  #include <stdlib.h>
  
+ #ifdef STRCASECMP_IN_STRINGS_H
+ #include <strings.h>
+ #endif
+ 
  /* Utility library. */
  
  #include <msg.h>
***************
*** 45,50 ****
--- 49,56 ----
  #include <tok822.h>
  #include <mail_params.h>
  #include <ext_prop.h>
+ #include <mail_addr.h>
+ #include <canon_addr.h>
  
  /* Application-specific. */
  
***************
*** 106,111 ****
--- 112,123 ----
  	    cleanup_fullname = mystrdup(STR(cleanup_inbuf));
  	} else if (type == REC_TYPE_FROM) {
  	    cleanup_rewrite_internal(clean_addr, STR(cleanup_inbuf));
+ 	    if (strncasecmp(STR(clean_addr), MAIL_ADDR_MAIL_DAEMON "@",
+ 			    sizeof(MAIL_ADDR_MAIL_DAEMON)) == 0) {
+ 		canon_addr_internal(cleanup_temp1, MAIL_ADDR_MAIL_DAEMON);
+ 		if (strcasecmp(STR(clean_addr), STR(cleanup_temp1)) == 0)
+ 		    vstring_strcpy(clean_addr, "");
+ 	    }
  	    if (cleanup_send_canon_maps)
  		cleanup_map11_internal(clean_addr, cleanup_send_canon_maps,
  				cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
diff -cr --new-file /tmp/postfix-19991231-pl07/cleanup/cleanup_masquerade.c ./cleanup/cleanup_masquerade.c
*** /tmp/postfix-19991231-pl07/cleanup/cleanup_masquerade.c	Tue Jan 19 09:02:22 1999
--- ./cleanup/cleanup_masquerade.c	Sun May 28 18:54:03 2000
***************
*** 99,105 ****
  	masq_except_table = htable_create(5);
  	ptr = saved_names = mystrdup(var_masq_exceptions);
  	while ((name = mystrtok(&ptr, ", \t\r\n")) != 0)
! 	    htable_enter(masq_except_table, name, (char *) 0);
  	myfree(saved_names);
      }
  
--- 99,105 ----
  	masq_except_table = htable_create(5);
  	ptr = saved_names = mystrdup(var_masq_exceptions);
  	while ((name = mystrtok(&ptr, ", \t\r\n")) != 0)
! 	    htable_enter(masq_except_table, lowercase(name), (char *) 0);
  	myfree(saved_names);
      }
  
***************
*** 116,122 ****
       */
      if (masq_except_table) {
  	name = mystrndup(STR(addr), domain - 1 - STR(addr));
! 	excluded = (htable_locate(masq_except_table, name) != 0);
  	myfree(name);
  	if (excluded)
  	    return;
--- 116,122 ----
       */
      if (masq_except_table) {
  	name = mystrndup(STR(addr), domain - 1 - STR(addr));
! 	excluded = (htable_locate(masq_except_table, lowercase(name)) != 0);
  	myfree(name);
  	if (excluded)
  	    return;
diff -cr --new-file /tmp/postfix-19991231-pl07/cleanup/cleanup_message.c ./cleanup/cleanup_message.c
*** /tmp/postfix-19991231-pl07/cleanup/cleanup_message.c	Thu Apr 13 17:23:31 2000
--- ./cleanup/cleanup_message.c	Sun May 28 21:20:35 2000
***************
*** 240,246 ****
  
  	if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) {
  	    if (strcasecmp(value, "REJECT") == 0) {
! 		msg_warn("%s: reject: header %.100s", cleanup_queue_id, header);
  		cleanup_errs |= CLEANUP_STAT_CONT;
  	    }
  	}
--- 240,246 ----
  
  	if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) {
  	    if (strcasecmp(value, "REJECT") == 0) {
! 		msg_warn("%s: reject: header %.200s", cleanup_queue_id, header);
  		cleanup_errs |= CLEANUP_STAT_CONT;
  	    }
  	}
***************
*** 460,465 ****
--- 460,487 ----
  	    if (in_header) {
  		vstring_strcpy(cleanup_header_buf, start);
  	    } else {
+ 
+ 		/*
+ 		 * Crude message body content filter for emergencies. This
+ 		 * code has several problems: it sees one line at a time, and
+ 		 * therefore does not recognize multi-line MIME headers in
+ 		 * the body; it looks at long lines only in chunks of
+ 		 * line_length_limit (2048) characters; it is easily bypassed
+ 		 * with encodings and with multi-line tricks.
+ 		 */
+ 		if ((cleanup_flags & CLEANUP_FLAG_FILTER)
+ 		    && cleanup_body_checks) {
+ 		    char   *body = vstring_str(cleanup_inbuf);
+ 		    const char *value;
+ 
+ 		    if ((value = maps_find(cleanup_body_checks, body, 0)) != 0) {
+ 			if (strcasecmp(value, "REJECT") == 0) {
+ 			    msg_warn("%s: reject: body %.200s",
+ 				     cleanup_queue_id, body);
+ 			    cleanup_errs |= CLEANUP_STAT_CONT;
+ 			}
+ 		    }
+ 		}
  		CLEANUP_OUT_BUF(type, cleanup_inbuf);
  	    }
  	}
diff -cr --new-file /tmp/postfix-19991231-pl07/conf/sample-filter.cf ./conf/sample-filter.cf
*** /tmp/postfix-19991231-pl07/conf/sample-filter.cf	Wed Dec 31 19:00:00 1969
--- ./conf/sample-filter.cf	Sun May 28 18:57:56 2000
***************
*** 0 ****
--- 1,24 ----
+ # DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+ # HERE JUST SERVES AS AN EXAMPLE.
+ #
+ # This file contains example settings for miscellaneous Postfix
+ # content filtering parameters.
+ 
+ # The header_checks parameter specifies an optional table with patterns
+ # that each logical message header is matched against, including
+ # headers that span multiple physical lines.  Patterns are matched
+ # in the specified order, and the search stops upon the first match.
+ # When a pattern matches, and the associated action is REJECT, the
+ # entire message is rejected.
+ #
+ header_checks = regexp:/etc/postfix/header_checks
+ 
+ # The body_checks parameter specifies an optional table with patterns
+ # that each physical non-header line is matched against (including
+ # MIME headers inside the message body).  Lines are matched one at
+ # a time.  Long lines are matched in chunks of at most $line_length_limit
+ # characters. Patterns are matched in the specified order, and the
+ # search stops upon the first match.  When a pattern matches, and
+ # the associated action is REJECT, the entire message is rejected.
+ #
+ body_checks = regexp:/etc/postfix/body_checks
diff -cr --new-file /tmp/postfix-19991231-pl07/global/mail_params.h ./global/mail_params.h
*** /tmp/postfix-19991231-pl07/global/mail_params.h	Sun Apr 16 12:00:49 2000
--- ./global/mail_params.h	Sun May 28 18:52:09 2000
***************
*** 661,666 ****
--- 661,670 ----
  #define DEF_HEADER_CHECKS	""
  extern char *var_header_checks;
  
+ #define VAR_BODY_CHECKS		"body_checks"
+ #define DEF_BODY_CHECKS		""
+ extern char *var_body_checks;
+ 
   /*
    * Bounce service: truncate bounce message that exceed $bounce_size_limit.
    */