[comp.sources.bugs] Deliver 1.00 patch #8

chip@ateng.ateng.com (Chip Salzenberg) (02/16/89)

This is an offical patch for deliver 1.00.  Please apply it.

Patch number:   8
Date:           15 Feb 1989
Priority:       HIGH
Changes:
	There was a really awful bug in do_dfile() which causes an infinite
	loop -- and thus loss of mail -- if a delivery file outputs
	any white space!  I wonder why it took this long to find?

        Some people have lamented the lack of an alias file in deliver.
        Okay!  Deliver now has system-wide aliasing.  However, instead of
        writing YAAFP (yet another alias file parser), I simply added
	another system-wide delivery file.  This new file is called the
        "post-user delivery file" (clever name, huh?).  It is executed after
        any user delivery files, but before the message is actually written
        to any mailboxes.

	The documentation is updated to reflect old and new features.

Index: patchlevel.h
Prereq: 7
***************
*** 1 ****
! #define PATCHLEVEL 7
--- 1 ----
! #define PATCHLEVEL 8

Index: config.h
***************
*** 1,8 ****
! /* $Header: config.h,v 1.8 89/02/10 18:08:24 network Exp $
   *
   * Deliver configuration.
   *
   * $Log:	config.h,v $
   * Revision 1.8  89/02/10  18:08:24  network
   * Fix location of mailboxes.
   * 
--- 1,15 ----
! /* $Header: config.h,v 1.9 89/02/15 19:09:37 network Exp $
   *
   * Deliver configuration.
   *
   * $Log:	config.h,v $
+  * Revision 1.9  89/02/15  19:09:37  network
+  * Provide second system-wide delivery file, executed after user delivery
+  * files but before any deliveries take place.  Useful for implementing
+  * system-wide aliases.
+  * Also, fix bug in do_dfile() that caused infinite loops if delivery files
+  * output any lines containing white space. (!)
+  * 
   * Revision 1.8  89/02/10  18:08:24  network
   * Fix location of mailboxes.
   * 
***************
*** 194,200 ****
   * (This string should include all metacharacters for your chosen shell.)
   */
  
! #define SANITIZE   "$*?=\\`'\"|^&;{}()<>"
  
  /*----------------------------------------------------------------------
   * Standard mailbox location.
--- 201,207 ----
   * (This string should include all metacharacters for your chosen shell.)
   */
  
! #define SANITIZE   "$*?=\\`'\"|^&;{}()<> \t\n"
  
  /*----------------------------------------------------------------------
   * Standard mailbox location.
***************
*** 228,250 ****
   * Names of delivery files.
   *
   * SYS_DELIVER          system-wide delivery file
   * USER_DELIVER         user delivery file (in user's home directory)
   */
  
  #define SYS_DELIVER     "/usr/local/lib/deliver.sys"
  #define USER_DELIVER    ".deliver"
  
  /*----------------------------------------------------------------------
   * Environment variables passed to child processes.
-  * Variables marked with [#] are created only if they are specified
-  * as command line options.
   */
  
  #define ENV_DFLAGS      "DELFLAGS"      /* Flags: [-[Avdt]]             */
! #define ENV_SYSDEL      "SYSDELFILE"    /* System delivery file [#]     */
! #define ENV_USERDEL     "USERDELFILE"   /* User delivery file [#]       */
  
  #define ENV_HOSTNAME    "HOSTNAME"      /* Name of this host            */
! #define ENV_SENDER      "SENDER"        /* Message sender [#]           */
  #define ENV_HEADER      "HEADER"        /* Message header file          */
  #define ENV_BODY        "BODY"          /* Message body file            */
--- 235,258 ----
   * Names of delivery files.
   *
   * SYS_DELIVER          system-wide delivery file
+  * POST_DELIVER         post-user delivery file
   * USER_DELIVER         user delivery file (in user's home directory)
   */
  
  #define SYS_DELIVER     "/usr/local/lib/deliver.sys"
+ #define POST_DELIVER    "/usr/local/lib/deliver.post"
  #define USER_DELIVER    ".deliver"
  
  /*----------------------------------------------------------------------
   * Environment variables passed to child processes.
   */
  
  #define ENV_DFLAGS      "DELFLAGS"      /* Flags: [-[Avdt]]             */
! #define ENV_SYSDEL      "SYSDELFILE"    /* System delivery file         */
! #define ENV_POSTDEL     "POSTDELFILE"   /* Post-user delivery file      */
! #define ENV_USERDEL     "USERDELFILE"   /* User delivery file           */
  
  #define ENV_HOSTNAME    "HOSTNAME"      /* Name of this host            */
! #define ENV_SENDER      "SENDER"        /* Message sender               */
  #define ENV_HEADER      "HEADER"        /* Message header file          */
  #define ENV_BODY        "BODY"          /* Message body file            */

Index: deliver.8
***************
*** 1,8 ****
! .\" $Header: deliver.8,v 1.5 88/10/13 13:44:03 network Exp $
  .\"
  .\" Man page for deliver.
  .\"
  .\" $Log:	deliver.8,v $
  .\" Revision 1.5  88/10/13  13:44:03  network
  .\" patch1: rework the whole man page.
  .\" 
--- 1,18 ----
! .\" $Header: deliver.8,v 1.7 89/02/15 19:31:32 network Exp $
  .\"
  .\" Man page for deliver.
  .\"
  .\" $Log:	deliver.8,v $
+ .\" Revision 1.7  89/02/15  19:31:32  network
+ .\" Complete documentation of recent features.
+ .\" 
+ .\" Revision 1.6  89/02/15  19:10:54  network
+ .\" Provide second system-wide delivery file, executed after user delivery
+ .\" files but before any deliveries take place.  Useful for implementing
+ .\" system-wide aliases.
+ .\" Also, fix bug in do_dfile() that caused infinite loops if delivery files
+ .\" output any lines containing white space. (!)
+ .\" 
  .\" Revision 1.5  88/10/13  13:44:03  network
  .\" patch1: rework the whole man page.
  .\" 
***************
*** 94,99 ****
--- 104,114 ----
  .I /usr/local/lib/deliver.sys.
  For security reasons, this option disables setuid privileges.
  .TP
+ .BI \-p " post-user delivery file"
+ Specify an alternate post-user delivery file.  The default is
+ .I /usr/local/lib/deliver.post.
+ For security reasons, this option disables setuid privileges.
+ .TP
  .BI \-u " user delivery file"
  Specify an alternate user delivery file.  The default is
  .I .deliver
***************
*** 176,182 ****
  After possibly executing the system delivery file,
  .I deliver
  looks in its list of destinations for valid user names without explicitly
! named mailboxes.  If any of the named users have user delivery files in
  their home directories, and if the
  .B \-n
  option was not specified,
--- 191,197 ----
  After possibly executing the system delivery file,
  .I deliver
  looks in its list of destinations for valid user names without explicitly
! named mailboxes.  If any of these users have user delivery files in
  their home directories, and if the
  .B \-n
  option was not specified,
***************
*** 183,188 ****
--- 198,213 ----
  .I deliver
  executes each user delivery file with the name of the given user as its
  only argument.
+ .PP
+ After executing any user delivery files,
+ .I deliver
+ looks in its list of destinations for simple user names and UUCP
+ addresses.  If any are found, if the post-user delivery file exists,
+ and if the
+ .B \-n
+ option was not specified,
+ .I deliver
+ executes the post-user delivery file with these addresses as its arguments.
  .SH "DELIVERY FILES"
  Delivery files are shell scripts.  They are executed by
  .I deliver
***************
*** 198,204 ****
  .I deliver
  command line as its arguments.
  .PP
! In addition, each user may create a
  .I user delivery file
  in his home directory.  User delivery files are always executed with exactly
  one argument: the name of the user in whose home directory the file is
--- 223,236 ----
  .I deliver
  command line as its arguments.
  .PP
! The postmaster may also create a
! .I post-user delivery file
! which is executed after any user delivery files, but before delivery of the
! message to any mailboxes.  This file is particularly useful for implementing
! system-wide aliases, since it can deal with addresses generated by user
! delivery files, whereas the system delivery file cannot.
! .PP
! Finally, each user may create a
  .I user delivery file
  in his home directory.  User delivery files are always executed with exactly
  one argument: the name of the user in whose home directory the file is
***************
*** 240,247 ****
  .B SYSDELFILE
  The system delivery filename.
  .TP
  .B USERDELFILE
! The user delivery filename.
  .TP
  .B HOSTNAME
  The local host name, either the real hostname or a name specified with the
--- 272,282 ----
  .B SYSDELFILE
  The system delivery filename.
  .TP
+ .B POSTDELFILE
+ The post-user delivery filename.
+ .TP
  .B USERDELFILE
! The user delivery filename, relative to the home directory of each user.
  .TP
  .B HOSTNAME
  The local host name, either the real hostname or a name specified with the
***************
*** 250,258 ****
  .I deliver.
  .TP
  .B SENDER
! The sender, if any, specified with the
  .B \-r
  option to
  .I deliver.
  .TP
  .B HEADER
--- 285,296 ----
  .I deliver.
  .TP
  .B SENDER
! The sender, either an address specified with
  .B \-r
  option to
+ .I deliver,
+ or the address given in the From_ line of the message, or the user who
+ invoked
  .I deliver.
  .TP
  .B HEADER
***************
*** 303,309 ****
  .B NOTE 4:
  For security reasons, if a user's home directory is writable to the world,
  .I deliver
! will ignore any deliver file that might be found there.
  .PP
  .B NOTE 5:
  For security reasons,
--- 341,347 ----
  .B NOTE 4:
  For security reasons, if a user's home directory is writable to the world,
  .I deliver
! will ignore any delivery file that might be found there.
  .PP
  .B NOTE 5:
  For security reasons,
***************
*** 344,349 ****
--- 382,389 ----
  ML_LOCKF, ML_FCNTL or ML_LOCKING may be specified.
  .SH FILES
  /usr/local/lib/deliver.sys      system delivery file
+ .br
+ /usr/local/lib/deliver.post     post-user delivery file
  .br
  ~user/.deliver                  user delivery file(s)
  .br

Index: deliver.h
***************
*** 1,8 ****
! /* $Header: deliver.h,v 1.7 89/02/10 15:46:27 network Exp $
   *
   * General pull-it-together include file.
   *
   * $Log:	deliver.h,v $
   * Revision 1.7  89/02/10  15:46:27  network
   * V7 support.
   * 
--- 1,15 ----
! /* $Header: deliver.h,v 1.8 89/02/15 19:11:07 network Exp $
   *
   * General pull-it-together include file.
   *
   * $Log:	deliver.h,v $
+  * Revision 1.8  89/02/15  19:11:07  network
+  * Provide second system-wide delivery file, executed after user delivery
+  * files but before any deliveries take place.  Useful for implementing
+  * system-wide aliases.
+  * Also, fix bug in do_dfile() that caused infinite loops if delivery files
+  * output any lines containing white space. (!)
+  * 
   * Revision 1.7  89/02/10  15:46:27  network
   * V7 support.
   * 
***************
*** 54,59 ****
--- 61,67 ----
  extern  char    *hostname;      /* Name of this host                    */
  
  extern  char    *sys_deliver;   /* Systemwide delivery file             */
+ extern  char    *post_deliver;  /* Post-user delivery file              */
  extern  char    *user_deliver;  /* User delivery file                   */
  extern  char    *shell;         /* Shell used to run delivery files     */
  

Index: dfile.c
***************
*** 1,8 ****
! /* $Header: dfile.c,v 1.7 89/02/10 15:46:42 network Exp $
   *
   * Filter destination(s) through delivery file(s).
   *
   * $Log:	dfile.c,v $
   * Revision 1.7  89/02/10  15:46:42  network
   * V7 support.
   * 
--- 1,15 ----
! /* $Header: dfile.c,v 1.8 89/02/15 19:11:12 network Exp $
   *
   * Filter destination(s) through delivery file(s).
   *
   * $Log:	dfile.c,v $
+  * Revision 1.8  89/02/15  19:11:12  network
+  * Provide second system-wide delivery file, executed after user delivery
+  * files but before any deliveries take place.  Useful for implementing
+  * system-wide aliases.
+  * Also, fix bug in do_dfile() that caused infinite loops if delivery files
+  * output any lines containing white space. (!)
+  * 
   * Revision 1.7  89/02/10  15:46:42  network
   * V7 support.
   * 
***************
*** 46,75 ****
  char    **dav;
  {
  	char    **fav;
! 	int     fac, a, goodnames;
  	struct stat st;
  
  	/*
! 	 * If we've been asked not to run delivery files, forget it.
  	 */
  
! 	if (!rundfiles)
  	{
  		if (verbose)
! 			message("system delivery file disabled\n");
! 
  		return -1;
  	}
  
  	/*
! 	 * If there is no global delivery file, forget it.
  	 */
  
! 	if (stat(sys_deliver, &st) == -1)
  	{
  		if (verbose)
! 			message("no system delivery file\n");
! 
  		return -1;
  	}
  
--- 53,80 ----
  char    **dav;
  {
  	char    **fav;
! 	int     fac, a;
  	struct stat st;
  
  	/*
! 	 * If there is no global delivery file, forget it.
  	 */
  
! 	if (stat(sys_deliver, &st) == -1)
  	{
  		if (verbose)
! 			message("no system delivery file\n");
  		return -1;
  	}
  
  	/*
! 	 * If we've been asked not to run delivery files, forget it.
  	 */
  
! 	if (!rundfiles)
  	{
  		if (verbose)
! 			message("system delivery file disabled\n");
  		return -1;
  	}
  
***************
*** 82,88 ****
  	fav[1] = sys_deliver;
  	fac = 2;
  
- 	goodnames = 0;
  	for (a = 0; a < dac; ++a)
  	{
  		char    *addr;
--- 87,92 ----
***************
*** 93,99 ****
  			/* Let the delivery file handle valid addresses. */
  
  			fav[fac++] = addr;
- 			++goodnames;
  		}
  		else
  		{
--- 97,102 ----
***************
*** 112,118 ****
  	 * all local deliveries, not just those to valid users.
  	 */
  
! 	if (goodnames)
  		(void) do_dfile(eff_ct, fav, (DEST *)NULL);
  
  	free((char *) fav);
--- 115,121 ----
  	 * all local deliveries, not just those to valid users.
  	 */
  
! 	if (fac > 2)
  		(void) do_dfile(eff_ct, fav, (DEST *)NULL);
  
  	free((char *) fav);
***************
*** 121,126 ****
--- 124,197 ----
  }
  
  /*----------------------------------------------------------------------
+  * Filter some undelivered destinations through the post-user
+  * delivery file.
+  */
+ 
+ post_dfile()
+ {
+ 	DEST    *d;
+ 	char    **fav;
+ 	int     num_dests, fac;
+ 	struct stat st;
+ 
+ 	/*
+ 	 * If there is no post-user delivery file, forget it.
+ 	 */
+ 
+ 	if (stat(post_deliver, &st) == -1)
+ 	{
+ 		if (verbose)
+ 			message("no post-user delivery file\n");
+ 		return -1;
+ 	}
+ 
+ 	/*
+ 	 * If we've been asked not to run delivery files, forget it.
+ 	 */
+ 
+ 	if (!rundfiles)
+ 	{
+ 		if (verbose)
+ 			message("post-user delivery file disabled\n");
+ 		return -1;
+ 	}
+ 
+ 	/*
+ 	 * Generate the delivery file argument list.
+ 	 */
+ 
+ 	num_dests = 0;
+ 	for (d = first_dest(); d; d = next_dest(d))
+ 		++num_dests;
+ 
+ 	fav = (char **) zalloc((num_dests + 3) * sizeof(char **));
+ 	fav[0] = shell;
+ 	fav[1] = post_deliver;
+ 	fac = 2;
+ 
+ 	for (d = first_dest(); d; d = next_dest(d))
+ 	{
+ 		if ((d->d_class == CL_USER || d->d_class == CL_UUCP)
+ 		 && (d->d_state == ST_WORKING
+ 		  || (d->d_state == ST_ERROR && d->d_error == E_NSUSER)))
+ 		{
+ 			fav[fac++] = d->d_name;
+ 			d->d_state = ST_HOLD;
+ 		}
+ 	}
+ 
+ 	fav[fac] = NULL;
+ 
+ 	if (fac > 2)
+ 		(void) do_dfile(eff_ct, fav, (DEST *)NULL);
+ 
+ 	free((char *) fav);
+ 
+ 	return 0;
+ }
+ 
+ /*----------------------------------------------------------------------
   * Filter all user destinations through their local delivery files.
   */
  
***************
*** 277,283 ****
  	if ((fp = ct_popenv(ct, shell, av, "r")) == NULL)
  	{
  		error("can't execute delivery file as %s\n", ct->ct_name);
! 		leave(1);
  	}
  
  	/*
--- 348,354 ----
  	if ((fp = ct_popenv(ct, shell, av, "r")) == NULL)
  	{
  		error("can't execute delivery file as %s\n", ct->ct_name);
! 		return -1;
  	}
  
  	/*
***************
*** 346,358 ****
  	p = q = buf;
  	while (*p)
  	{
! 		if (! isspace(*p))
  		{
! 			if ((*q++ = *p++) == '/')
! 			{
! 				while (*p == '/')
! 					++p;
! 			}
  		}
  	}
  	*q = 0;
--- 417,428 ----
  	p = q = buf;
  	while (*p)
  	{
! 		if (isspace(*p))
! 			++p;
! 		else if ((*q++ = *p++) == '/')
  		{
! 			while (*p == '/')
! 				++p;
  		}
  	}
  	*q = 0;

Index: main.c
***************
*** 1,8 ****
! /* $Header: main.c,v 1.10 89/02/10 15:46:59 network Exp $
   *
   * A program to deliver local mail with some flexibility.
   *
   * $Log:	main.c,v $
   * Revision 1.10  89/02/10  15:46:59  network
   * V7 support.
   * 
--- 1,15 ----
! /* $Header: main.c,v 1.11 89/02/15 19:11:25 network Exp $
   *
   * A program to deliver local mail with some flexibility.
   *
   * $Log:	main.c,v $
+  * Revision 1.11  89/02/15  19:11:25  network
+  * Provide second system-wide delivery file, executed after user delivery
+  * files but before any deliveries take place.  Useful for implementing
+  * system-wide aliases.
+  * Also, fix bug in do_dfile() that caused infinite loops if delivery files
+  * output any lines containing white space. (!)
+  * 
   * Revision 1.10  89/02/10  15:46:59  network
   * V7 support.
   * 
***************
*** 63,68 ****
--- 70,76 ----
   */
  
  static  char    sys_dfl[] = SYS_DELIVER;
+ static  char    post_dfl[] = POST_DELIVER;
  static  char    user_dfl[] = USER_DELIVER;
  
  /*
***************
*** 81,86 ****
--- 89,95 ----
  char    *shell          = SHELL;
  
  char    *sys_deliver    = sys_dfl;
+ char    *post_deliver   = post_dfl;
  char    *user_deliver   = user_dfl;
  char    *sender         = NULL;
  char    *hostname       = NULL;
***************
*** 187,192 ****
--- 196,203 ----
  
  	if ((p = getenv(ENV_SYSDEL)) != NULL && *p)
  		sys_deliver = p;
+ 	if ((p = getenv(ENV_POSTDEL)) != NULL && *p)
+ 		post_deliver = p;
  	if ((p = getenv(ENV_USERDEL)) != NULL && *p)
  		user_deliver = p;
  	if ((p = getenv(ENV_SENDER)) != NULL && *p)
***************
*** 196,202 ****
  
  	/* Parse command line arguments */
  
! 	while ((c = getopt(argc, argv, "vdAntbs:u:r:h:")) != EOF)
  	{
  		switch (c)
  		{
--- 207,213 ----
  
  	/* Parse command line arguments */
  
! 	while ((c = getopt(argc, argv, "vdAntbs:p:u:r:h:")) != EOF)
  	{
  		switch (c)
  		{
***************
*** 224,229 ****
--- 235,244 ----
  			if (*optarg)
  				sys_deliver = optarg;
  			break;
+ 		case 'p':
+ 			if (*optarg)
+ 				post_deliver = optarg;
+ 			break;
  		case 'u':
  			if (*optarg)
  				user_deliver = optarg;
***************
*** 265,270 ****
--- 280,286 ----
  	/* Do we trust our delivery files? */
  
  	if (strcmp(sys_dfl, sys_deliver) == 0
+ 	 && strcmp(post_dfl, post_deliver) == 0
  	 && strcmp(user_dfl, user_deliver) == 0)
  		trust_delfiles = TRUE;
  
***************
*** 415,420 ****
--- 431,447 ----
  			if (verbose)
  				dumpdests("after running user delivery files");
  		}
+ 
+ 		/*
+ 		 * Run each remaining destination though the post-user
+ 		 * delivery file.
+ 		 */
+ 
+ 		if (post_dfile() >= 0)
+ 		{
+ 			if (verbose)
+ 				dumpdests("after running post-user delivery file");
+ 		}
  	}
  
  	/*
***************
*** 464,469 ****
--- 491,497 ----
  	message("-n       Do not run any delivery files.\n");
  	message("-t       Do not remote temp files before exiting.\n");
  	message("-s file  Specify the system delivery filename.\n");
+ 	message("-p file  Specify the post-user delivery filename.\n");
  	message("-u file  Specify the user delivery filename.\n");
  	message("-r from  Specify the address to appear in the \"From \" line.\n");
  	message("-h host  Specify the host name.\n");
-- 
Chip Salzenberg             <chip@ateng.com> or <uunet!ateng!chip>
A T Engineering             Me?  Speak for my company?  Surely you jest!
	  "It's no good.  They're tapping the lines."