Subject: Postfix 19990906 Patch 09

From: [email-masked] (Wietse Venema)
Date: Sat, 11 Dec 1999 20:18:06 -0500 (EST)

This patch resolves several really old defects that were resolved
or discovered in the last couple weeks.

  - Address rewriting would panic on a lone \ at the end of a line
    where an address was expected. Reported by Jason Hoos.

  - The local delivery agent would deliver to the user instead of
    the .forward file when the .forward file was already visited
    via some non-recursive path. Patch by Patrik Rak.

  - Postfix now attempts to deliver all addresses in the expansion
    of an alias or .forward file, even when some addresses must be
    deferred. Problem reported by Andrew McNamara and others.

A patch is appended below the signature. A complete source kit,
postfix-19990906-pl09.tar.gz, will be made available from the
primary site:

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

including a PGP signature (postfix-19990906-pl09.tar.gz.sig). 

These files are expected to arrive on the Postfix download sites
in a day or so. See http://www.postfix.org/ for a list of download
sites.

	Wietse

Prereq: "Postfix-19990906-pl08"
diff -cr /tmp/postfix-19990906-pl08/global/mail_version.h ./global/mail_version.h
*** /tmp/postfix-19990906-pl08/global/mail_version.h	Sun Nov 21 21:52:03 1999
--- ./global/mail_version.h	Sat Dec 11 19:21:02 1999
***************
*** 15,21 ****
    * Version of this program.
    */
  #define VAR_MAIL_VERSION	"mail_version"
! #define DEF_MAIL_VERSION	"Postfix-19990906-pl08"
  extern char *var_mail_version;
  
  /* LICENSE
--- 15,21 ----
    * Version of this program.
    */
  #define VAR_MAIL_VERSION	"mail_version"
! #define DEF_MAIL_VERSION	"Postfix-19990906-pl09"
  extern char *var_mail_version;
  
  /* LICENSE
diff -cr /tmp/postfix-19990906-pl08/global/been_here.c ./global/been_here.c
*** /tmp/postfix-19990906-pl08/global/been_here.c	Fri Dec 11 13:55:23 1998
--- ./global/been_here.c	Sat Dec 11 19:40:19 1999
***************
*** 17,22 ****
--- 17,30 ----
  /*	BH_TABLE *dup_filter;
  /*	char	*format;
  /*
+ /*	int	been_here_check_fixed(dup_filter, string)
+ /*	BH_TABLE *dup_filter;
+ /*	char	*string;
+ /*
+ /*	int	been_here_check(dup_filter, format, ...)
+ /*	BH_TABLE *dup_filter;
+ /*	char	*format;
+ /*
  /*	void	been_here_free(dup_filter)
  /*	BH_TABLE *dup_filter;
  /* DESCRIPTION
***************
*** 34,39 ****
--- 42,50 ----
  /*	not found. The result is non-zero (true) if the formatted result was
  /*	found, zero (false) otherwise.
  /*
+ /*	been_here_check_fixed() and been_here_check() are similar
+ /*	but do not update the duplicate filter.
+ /*
  /*	been_here_free() releases storage for a duplicate filter.
  /*
  /*	Arguments:
***************
*** 157,169 ****
      if (htable_locate(dup_filter->table, lookup_key) != 0) {
  	status = 1;
      } else {
! 	if (dup_filter->limit > 0
! 	    && dup_filter->limit > dup_filter->table->used)
  	    htable_enter(dup_filter->table, lookup_key, (char *) 0);
  	status = 0;
      }
      if (msg_verbose)
  	msg_info("been_here: %s: %d", string, status);
  
      /*
       * Cleanup.
--- 168,242 ----
      if (htable_locate(dup_filter->table, lookup_key) != 0) {
  	status = 1;
      } else {
! 	if (dup_filter->limit <= 0
! 	    || dup_filter->limit > dup_filter->table->used)
  	    htable_enter(dup_filter->table, lookup_key, (char *) 0);
  	status = 0;
      }
      if (msg_verbose)
  	msg_info("been_here: %s: %d", string, status);
+ 
+     /*
+      * Cleanup.
+      */
+     if (folded_string)
+ 	myfree(folded_string);
+ 
+     return (status);
+ }
+ 
+ /* been_here_check - query duplicate detector with finer control */
+ 
+ int     been_here_check(BH_TABLE *dup_filter, const char *fmt,...)
+ {
+     VSTRING *buf = vstring_alloc(100);
+     int     status;
+     va_list ap;
+ 
+     /*
+      * Construct the string to be checked.
+      */
+     va_start(ap, fmt);
+     vstring_vsprintf(buf, fmt, ap);
+     va_end(ap);
+ 
+     /*
+      * Do the duplicate check.
+      */
+     status = been_here_check_fixed(dup_filter, vstring_str(buf));
+ 
+     /*
+      * Cleanup.
+      */
+     vstring_free(buf);
+     return (status);
+ }
+ 
+ /* been_here_check_fixed - query duplicate detector */
+ 
+ int     been_here_check_fixed(BH_TABLE *dup_filter, const char *string)
+ {
+     char   *folded_string;
+     const char *lookup_key;
+     int     status;
+ 
+     /*
+      * Special processing: case insensitive lookup.
+      */
+     if (dup_filter->flags & BH_FLAG_FOLD) {
+ 	folded_string = mystrdup(string);
+ 	lookup_key = lowercase(folded_string);
+     } else {
+ 	folded_string = 0;
+ 	lookup_key = string;
+     }
+ 
+     /*
+      * Do the duplicate check.
+      */
+     status = (htable_locate(dup_filter->table, lookup_key) != 0);
+     if (msg_verbose)
+ 	msg_info("been_here_check: %s: %d", string, status);
  
      /*
       * Cleanup.
diff -cr /tmp/postfix-19990906-pl08/global/been_here.h ./global/been_here.h
*** /tmp/postfix-19990906-pl08/global/been_here.h	Fri Dec 11 13:55:22 1998
--- ./global/been_here.h	Sat Dec 11 19:40:19 1999
***************
*** 32,37 ****
--- 32,39 ----
  extern void been_here_free(BH_TABLE *);
  extern int been_here_fixed(BH_TABLE *, const char *);
  extern int been_here(BH_TABLE *, const char *,...);
+ extern int been_here_check_fixed(BH_TABLE *, const char *);
+ extern int been_here_check(BH_TABLE *, const char *,...);
  
  /* LICENSE
  /* .ad
diff -cr /tmp/postfix-19990906-pl08/global/rewrite_clnt.c ./global/rewrite_clnt.c
*** /tmp/postfix-19990906-pl08/global/rewrite_clnt.c	Sun Apr 25 18:05:42 1999
--- ./global/rewrite_clnt.c	Sat Dec 11 19:21:28 1999
***************
*** 85,91 ****
  #define STR vstring_str
  
      if (*addr == 0)
! 	msg_panic("rewrite_clnt: empty address");
      if (addr == STR(result))
  	msg_panic("rewrite_clnt: result clobbers input");
  
--- 85,91 ----
  #define STR vstring_str
  
      if (*addr == 0)
! 	addr = "";
      if (addr == STR(result))
  	msg_panic("rewrite_clnt: result clobbers input");
  
diff -cr /tmp/postfix-19990906-pl08/local/dotforward.c ./local/dotforward.c
*** /tmp/postfix-19990906-pl08/local/dotforward.c	Tue Aug 31 16:31:16 1999
--- ./local/dotforward.c	Sat Dec 11 19:34:26 1999
***************
*** 213,239 ****
       * If this user includes (an alias of) herself in her own .forward file,
       * deliver to the user instead.
       */
!     if (lookup_status >= 0
! 	&& been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
! 	state.msg_attr.exp_from = state.msg_attr.local;
! 	if (S_ISREG(st.st_mode) == 0) {
! 	    msg_warn("file %s is not a regular file", STR(path));
! 	} else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
! 	    msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
! 	} else if (st.st_mode & 002) {
! 	    msg_warn("file %s is world writable", STR(path));
! 	} else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
! 	    msg_warn("cannot open file %s: %m", STR(path));
! 	} else {
! 	    close_on_exec(fd, CLOSE_ON_EXEC);
! 	    addr_count = 0;
! 	    fp = vstream_fdopen(fd, O_RDONLY);
! 	    status = deliver_token_stream(state, usr_attr, fp, &addr_count);
! 	    if (vstream_fclose(fp))
! 		msg_warn("close file %s: %m", STR(path));
! 	    if (addr_count > 0)
! 		forward_found = YES;
! 	}
      }
  
      /*
--- 213,243 ----
       * If this user includes (an alias of) herself in her own .forward file,
       * deliver to the user instead.
       */
!     if (lookup_status >= 0) {
! 	if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
! 	    state.msg_attr.exp_from = state.msg_attr.local;
! 	    if (S_ISREG(st.st_mode) == 0) {
! 		msg_warn("file %s is not a regular file", STR(path));
! 	    } else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
! 		msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
! 	    } else if (st.st_mode & 002) {
! 		msg_warn("file %s is world writable", STR(path));
! 	    } else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
! 		msg_warn("cannot open file %s: %m", STR(path));
! 	    } else {
! 		close_on_exec(fd, CLOSE_ON_EXEC);
! 		addr_count = 0;
! 		fp = vstream_fdopen(fd, O_RDONLY);
! 		status = deliver_token_stream(state, usr_attr, fp, &addr_count);
! 		if (vstream_fclose(fp))
! 		    msg_warn("close file %s: %m", STR(path));
! 		if (addr_count > 0) {
! 		    forward_found = YES;
! 		    been_here(state.dup_filter, "forward-done %s", STR(path));
! 		}
! 	    }
! 	} else if (been_here_check(state.dup_filter, "forward-done %s", STR(path)) != 0)
! 	    forward_found = YES;		/* else we're recursive */
      }
  
      /*
diff -cr /tmp/postfix-19990906-pl08/local/recipient.c ./local/recipient.c
*** /tmp/postfix-19990906-pl08/local/recipient.c	Sun Jun 27 17:08:17 1999
--- ./local/recipient.c	Sat Dec 11 19:35:29 1999
***************
*** 222,227 ****
--- 222,234 ----
      state.msg_attr.unmatched = state.msg_attr.extension;
  
      /*
+      * Do not allow null usernames.
+      */
+     if (state.msg_attr.user[0] == 0)
+ 	return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ 			  "null username in %s", state.msg_attr.recipient));
+ 
+     /*
       * Run the recipient through the delivery switch.
       */
      if (msg_verbose)
diff -cr /tmp/postfix-19990906-pl08/local/token.c ./local/token.c
*** /tmp/postfix-19990906-pl08/local/token.c	Wed Jun 23 21:14:22 1999
--- ./local/token.c	Sat Dec 11 19:32:16 1999
***************
*** 177,185 ****
  	if (addr->type == TOK822_ADDR) {
  	    if (addr_count)
  		(*addr_count)++;
! 	    status = deliver_token(state, usr_attr, addr);
! 	    if (status != 0)
! 		break;
  	}
      }
      tok822_free_tree(tree);
--- 177,183 ----
  	if (addr->type == TOK822_ADDR) {
  	    if (addr_count)
  		(*addr_count)++;
! 	    status |= deliver_token(state, usr_attr, addr);
  	}
      }
      tok822_free_tree(tree);
diff -cr /tmp/postfix-19990906-pl08/HISTORY ./HISTORY
*** /tmp/postfix-19990906-pl08/HISTORY	Mon Nov 22 19:03:36 1999
--- ./HISTORY	Sat Dec 11 19:46:06 1999
***************
*** 3141,3146 ****
--- 3141,3151 ----
  	Documentation: removed spurious "do not edit" comments from
  	the sample pcre and regexp configuration files.
  
+ 19991113
+ 
+ 	Cleanup: the local delivery agent now explicitly rejects
+ 	recipients with an empty username.
+ 
  19991117
  
  	Portability: SunOS 4 has no SA_RESTART. File: util/watchdog.c.
***************
*** 3159,3161 ****
--- 3164,3189 ----
  	Bugfix: the LDAP client did not properly escape special
  	characters in lookup keys (patch by John Hensley).
  	File: util/dict_ldap.c.
+ 
+ 19991124
+ 
+ 	Bugfix: the local delivery agent's recipient duplicate
+ 	filter did not work when configured to use unlimited memory
+ 	(which is not a recommended setting). Patrik Rak @ein.cz.
+ 
+ 19991208
+ 
+ 	Bugfix: the local delivery agent would deliver to the user
+ 	instead of the .forward file when the .forward file was
+ 	already visited via some non-recursive path. Patch by Patrik
+ 	Rak @ ein.cz. Files: global/been_here.c, local/dotforward.c.
+ 
+ 	Robustness: attempt to deliver all addresses in the expansion
+ 	of an alias or .forward file, even when some addresses must
+ 	be deferred.  File: local/token.c.
+ 
+ 19991211
+ 
+ 	Bugfix: address rewriting would panic on a lone \ at the
+ 	end of a line where an address was expected. Jason Hoos @
+ 	thwack.net. File: global/rewrite_clnt.c.