[comp.mail.misc] Deliver 2.0 Patch #9

chip@tct.uucp (Chip Salzenberg) (03/08/90)

NOTE:  THIS IS PART OF A COMBINED PATCH.  APPLY PATCHES 7-9 TOGETHER.

This patch contains changes to the following files:
	patchlevel.h
	main.c
	mbox.c
	procs.c
	subs.c
	sysdep.c
	uucp.c

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

Index: main.c
***************
*** 1,3 ****
! /* $Header: main.c,v 2.7 90/02/06 11:56:40 chip Exp $
   *
   * A program to deliver local mail with some flexibility.
--- 1,3 ----
! /* $Header: main.c,v 2.12 90/03/07 11:00:58 chip Exp $
   *
   * A program to deliver local mail with some flexibility.
***************
*** 4,7 ****
--- 4,28 ----
   *
   * $Log:	main.c,v $
+  * Revision 2.12  90/03/07  11:00:58  chip
+  * Debugging messages only when verbose.  (Sigh.)
+  * 
+  * Revision 2.11  90/03/06  13:11:53  chip
+  * Run error delivery file after normal delivery;
+  * then call delivery routines again afterward.
+  * 
+  * Revision 2.10  90/03/06  12:21:13  chip
+  * Move logging into log.c and address parsing into addr.c.
+  * New: error delivery file for messages that fail.
+  * Major rearrangement of delivery file code.
+  * 
+  * Revision 2.9  90/02/23  15:05:15  chip
+  * Clean up the setuid/setgid renunciation logic.
+  * 
+  * Revision 2.8  90/02/23  14:16:47  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.7  90/02/06  11:56:40  chip
   * Enforce MBX_MODE regardless of UMASK.
***************
*** 35,39 ****
  #include "patchlevel.h"
  #include <signal.h>
- #include <time.h>
  
  /*
--- 56,59 ----
***************
*** 50,56 ****
   */
  
! static  char    sys_dfl[] = SYS_DELIVER;
! static  char    post_dfl[] = POST_DELIVER;
! static  char    user_dfl[] = USER_DELIVER;
  
  /*
--- 70,77 ----
   */
  
! static  char    dfl_sys[] = SYS_DELIVER;
! static  char    dfl_post[] = POST_DELIVER;
! static  char    dfl_err[] = ERR_DELIVER;
! static  char    dfl_user[] = USER_DELIVER;
  
  /*
***************
*** 71,77 ****
  int     rec_level       = 0;
  int     rec_parent      = -1;
! char    *sys_deliver    = sys_dfl;
! char    *post_deliver   = post_dfl;
! char    *user_deliver   = user_dfl;
  char    *sender         = NULL;
  char    *hostname       = NULL;
--- 92,99 ----
  int     rec_level       = 0;
  int     rec_parent      = -1;
! char    *sys_deliver    = dfl_sys;
! char    *post_deliver   = dfl_post;
! char    *err_deliver    = dfl_err;
! char    *user_deliver   = dfl_user;
  char    *sender         = NULL;
  char    *hostname       = NULL;
***************
*** 87,91 ****
  int     trust_user      = FALSE;
  int     trust_delfiles  = FALSE;
- 
  FILE    *log            = NULL;
  char    *logfile        = NULL;
--- 109,112 ----
***************
*** 127,136 ****
  	progname = basename(argv[0]);
  
- #ifdef USG
- 	/* System V requires that we ask for the time zone.  Used later. */
- 
- 	tzset();
- #endif
- 
  	/* Special hack -- handle the recursion level and parent first. */
  
--- 148,151 ----
***************
*** 208,213 ****
--- 223,231 ----
  	if ((p = getenv(ENV_POSTDEL)) != NULL && *p)
  		post_deliver = p;
+ 	if ((p = getenv(ENV_ERRDEL)) != NULL && *p)
+ 		err_deliver = p;
  	if ((p = getenv(ENV_USERDEL)) != NULL && *p)
  		user_deliver = p;
+ 
  	if ((p = getenv(ENV_SENDER)) != NULL && *p)
  		sender = p;
***************
*** 217,221 ****
  	/* Parse command line arguments */
  
! 	while ((c = getopt(argc, argv, "vdAntbs:p:u:r:h:")) != EOF)
  	{
  		switch (c)
--- 235,239 ----
  	/* Parse command line arguments */
  
! 	while ((c = getopt(argc, argv, "vdAntbs:p:e:u:r:h:")) != EOF)
  	{
  		switch (c)
***************
*** 249,252 ****
--- 267,274 ----
  				post_deliver = optarg;
  			break;
+ 		case 'e':
+ 			if (*optarg)
+ 				err_deliver = optarg;
+ 			break;
  		case 'u':
  			if (*optarg)
***************
*** 266,290 ****
  	}
  
! #ifdef ERRLOG
! 	/* If we're delivering and not being verbose, keep an error log. */
  
! 	if (!dryrun && !verbose)
  	{
! 		errlogfile = tempfile();
! 		if ((errlog = ftcreate(errlogfile)) == NULL)
! 			syserr("can't create %s", errlogfile);
! 	}
! #endif
! 
! #ifdef LOG
! 	/* If we're delivering and the log file exists, keep data for it. */
! 
! 	if (!dryrun && exists(LOG))
! 	{
! 		logfile = tempfile();
! 		if ((log = ftcreate(logfile)) == NULL)
! 			syserr("can't create %s", logfile);
  	}
- #endif
  
  	/* If no destinations were given, forget it. */
--- 288,303 ----
  	}
  
! 	/* Open temporary log files. */
! 
! 	openlogs();
  
! 	/* Figure out the name of this host, unless we've been told. */
! 
! 	if (!hostname && (hostname = gethost()) == NULL)
  	{
! 		hostname = "unknown";
! 		error("unable to determine host name; using \"%s\"\n",
! 		      hostname);
  	}
  
  	/* If no destinations were given, forget it. */
***************
*** 296,309 ****
  	}
  
! 	/* Figure out the name of this host */
! 
! 	if ((hostname = gethost()) == NULL)
! 	{
! 		hostname = "unknown";
! 		error("unable to determine host name; using \"%s\"\n",
! 		      hostname);
! 	}
! 
! 	/* Print a debugging message */
  
  	if (verbose)
--- 309,313 ----
  	}
  
! 	/* If debugging, print a nice banner. */
  
  	if (verbose)
***************
*** 313,317 ****
  	}
  
! 	/* Do we trust our caller? */
  
  	if (trusted_uid(real_uid))
--- 317,325 ----
  	}
  
! 	/*
! 	 * Renounce setuid privileges if:
! 	 *   1.  We don't trust the real user id, OR
! 	 *   2.  The caller is using non-default delivery file names.
! 	 */
  
  	if (trusted_uid(real_uid))
***************
*** 318,334 ****
  		trust_user = TRUE;
  
! 	/* 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;
  
! 	/* Renounce special privileges if something insecure was requested. */
! 
! 	if (!trust_user && !trust_delfiles)
  	{
! 		if (setgid(eff_gid = real_gid) == -1
! 		 || setuid(eff_uid = real_uid) == -1)
  		{
  			syserr("can't renounce setuid privileges");
--- 326,339 ----
  		trust_user = TRUE;
  
! 	if (strcmp(dfl_sys, sys_deliver) == 0
! 	 && strcmp(dfl_post, post_deliver) == 0
! 	 && strcmp(dfl_err, err_deliver) == 0
! 	 && strcmp(dfl_user, user_deliver) == 0)
  		trust_delfiles = TRUE;
  
! 	if ((!trust_user && !trust_delfiles)
! 	 && (eff_uid != real_uid || eff_gid != real_gid))
  	{
! 		if (setuid(real_uid) == -1)
  		{
  			syserr("can't renounce setuid privileges");
***************
*** 335,338 ****
--- 340,358 ----
  			leave(1);
  		}
+ 		if (setgid(real_gid) == -1)
+ 		{
+ 			syserr("can't renounce setgid privileges");
+ 			leave(1);
+ 		}
+ 
+ 		if ((eff_uid = geteuid()) != real_uid
+ 		 || (eff_gid = getegid()) != real_gid)
+ 		{
+ 			error("kernel bug: can't renounce setuid/setgid");
+ 			leave(1);
+ 		}
+ 
+ 		if (verbose)
+ 			message("renounced setuid privileges\n");
  	}
  
***************
*** 410,530 ****
  
  	if (rec_level > REC_LIMIT)
! 	{
! 		error("recursion limit (%d) exceeded; writing to %s:%s",
! 		      REC_LIMIT, eff_ct->ct_name, MBX_UNDEL);
  
- 		(void) dest(eff_ct->ct_name, MBX_UNDEL);
- 	}
- 
  	/*
! 	 * Else, if all arguments are mailbox names...
  	 */
  
  	else if (boxdelivery)
! 	{
! 		int     a;
  
! 		if (verbose)
! 			message("mailbox delivery as %s\n", real_ct->ct_name);
  
! 		/*
! 		 * Consider all arguments as mailbox filenames.
! 		 */
  
! 		for (a = optind; a < argc; ++a)
! 			(void) dest(real_ct->ct_name, argv[a]);
  
  		if (verbose)
! 			dumpdests("(should all be mailboxes)");
  	}
  
  	/*
! 	 * Else, arguments are addresses.
  	 */
  
! 	else
! 	{
! 		/* Run all destinations though the system delivery file. */
  
! 		if (sys_dfile(argc - optind, argv + optind) >= 0)
! 		{
! 			if (verbose)
! 				dumpdests("after running system delivery file");
! 		}
! 		else
! 		{
! 			int     a;
! 
! 			/*
! 			 * System delivery file is missing or ignored.
! 			 * Use the argument list verbatim.
! 			 */
! 
! 			for (a = optind; a < argc; ++a)
! 				(void) dest(argv[a], (char *) NULL);
  
! 			if (verbose)
! 				dumpdests("as taken from argument list");
! 		}
  
! 		/*
! 		 * Run each user destination through his delivery file.
! 		 */
  
! 		if (user_dfiles() >= 0)
! 		{
! 			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");
! 		}
  	}
  
! 	/*
! 	 * Drop mail in mailbox(es).
! 	 */
  
! 	mbox_deliver();
  
! 	if (verbose)
! 		dumpdests("after delivery to all mailboxes");
  
  	/*
! 	 * Send mail to UUCP address(es).
! 	 */
  
! 	uucp_deliver();
  
  	if (verbose)
! 		dumpdests("after delivery to UUCP addresses");
! 
! 	/*
! 	 * Report all results in log file.
! 	 */
  
! 	if (log)
! 		logreport(argc - optind, argv + optind);
  
! 	/*
! 	 * Report any errors.
! 	 */
  
! 	errcount = report_errors();
  
! 	/*
! 	 * All done.
! 	 */
  
! 	leave(errcount ? 1 : 0);
! 	/* NOTREACHED */
  }
  
--- 430,583 ----
  
  	if (rec_level > REC_LIMIT)
! 		main_toodeep();
  
  	/*
! 	 * Else if the "-b" flag was specified, arguments are mailboxes.
  	 */
  
  	else if (boxdelivery)
! 		main_boxes(argc - optind, argv + optind);
  
! 	/*
! 	 * Otherwise, arguments are addresses.
! 	 */
  
! 	else
! 		main_addrs(argc - optind, argv + optind);
  
! 	/*
! 	 * Do all delivery.
! 	 * If anything happens, print a debugging message.
! 	 */
! 
! 	i = 0;
! 	i += (mbox_deliver() > 0);
! 	i += (prog_deliver() > 0);
! 	i += (uucp_deliver() > 0);
! 	if (i > 0 && verbose)
! 		dumpdests("after delivery");
! 
! 	/*
! 	 * If we're not in mailbox mode, and if the error delivery file
! 	 * executes, deliver to any destination(s) that it generated.
! 	 */
  
+ 	if (!boxdelivery
+ 	 && (i = err_dfile()) > 0)
+ 	{
  		if (verbose)
! 			dumpdests("after running error delivery file");
! 
! 		i = 0;
! 		i += (mbox_deliver() > 0);
! 		i += (prog_deliver() > 0);
! 		i += (uucp_deliver() > 0);
! 		if (i > 0 && verbose)
! 			dumpdests("after delivery to error destinations");
  	}
  
  	/*
! 	 * Report all results in log file.
  	 */
  
! 	logreport(argc - optind, argv + optind);
  
! 	/*
! 	 * Report any errors.
! 	 */
  
! 	errcount = report_errors(argc - optind, argv + optind);
  
! 	/*
! 	 * All done.
! 	 */
  
! 	leave(errcount ? 1 : 0);
! 	/* NOTREACHED */
! }
  
! /*----------------------------------------------------------------------
!  * Normal address handling.
!  * Call system delivery file, user delivery files,
!  * post-user delivery file, error delivery file.
!  */
  
! main_addrs(ac, av)
! int	ac;
! char	**av;
! {
! 	int	n;
! 
! 	/* Run all destinations though the system delivery file. */
! 
! 	if (sys_dfile(ac, av) >= 0)
! 	{
! 		if (verbose)
! 			dumpdests("after running system delivery file");
  	}
+ 	else
+ 	{
+ 		int     a;
  
! 		/*
! 		 * System delivery file is missing or ignored.
! 		 * Use the argument list verbatim.
! 		 */
  
! 		for (a = 0; a < ac; ++a)
! 			(void) addr_dest(av[a], (CONTEXT *)NULL);
  
! 		if (verbose)
! 			dumpdests("as taken from argument list");
! 	}
  
  	/*
! 	 * Run each user destination through his delivery file.
! 	 */
! 
! 	n = user_dfiles();
! 	if (n > 0 && verbose)
! 		dumpdests("after running user delivery files");
! 
! 	/*
! 	 * Run each remaining destination though the post-user
! 	 * delivery file.
! 	 */
! 
! 	n = post_dfile();
! 	if (n > 0 && verbose)
! 		dumpdests("after running post-user delivery file");
! }
! 
! /*----------------------------------------------------------------------
!  * Consider all arguments as mailbox filenames.
!  */
  
! main_boxes(ac, av)
! int	ac;
! char	**av;
! {
! 	int     a;
  
  	if (verbose)
! 		message("mailbox delivery as %s\n", real_ct->ct_name);
  
! 	for (a = 0; a < ac; ++a)
! 		(void) dest(real_ct->ct_name, CL_MBOX, av[a]);
  
! 	if (verbose)
! 		dumpdests("(should all be mailboxes)");
! }
  
! /*----------------------------------------------------------------------
!  * Recursion too deep.  Bail out.
!  */
  
! main_toodeep()
! {
! 	error("recursion limit (%d) exceeded; writing to %s:%s",
! 	      REC_LIMIT, eff_ct->ct_name, MBX_UNDEL);
  
! 	dest_undel(eff_ct->ct_name);
  }
  
***************
*** 545,548 ****
--- 598,602 ----
  	message("-s file  Specify the system delivery filename.\n");
  	message("-p file  Specify the post-user delivery filename.\n");
+ 	message("-e file  Specify the error 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");
***************
*** 582,594 ****
  	savelogs();
  
! 	/* Discard temporary logs. */
  
! 	if (! leavetemps)
! 	{
! 		if (logfile && unlink(logfile) == -1)
! 			(void) syserr("can't remove %s", logfile);
! 		if (errlogfile && unlink(errlogfile) == -1)
! 			(void) syserr("can't remove %s", logfile);
! 	}
  
  	/* "I am outa here." */
--- 636,643 ----
  	savelogs();
  
! 	/* Discard temporary logs unless user requested otherwise. */
  
! 	if (!leavetemps)
! 		tosslogs();
  
  	/* "I am outa here." */
***************
*** 644,706 ****
  
  /*----------------------------------------------------------------------
-  * Write a report to the log file.
-  */
- 
- logreport(ac, av)
- int     ac;
- char    **av;
- {
- 	int     a;
- 
- 	if (!log)
- 		return;
- 
- 	logstart(log);
- 
- 	if (sender && *sender)
- 		(void) fprintf(log, "sender: %s\n", sender);
- 	if (boxdelivery)
- 		(void) fprintf(log, "mailbox%s:", (ac > 1) ? "es" : "");
- 	else
- 		(void) fprintf(log, "destination%s:", (ac > 1) ? "s" : "");
- 	for (a = 0; a < ac; ++a)
- 		(void) fprintf(log, " \"%s\"", av[a]);
- 	(void) fputc('\n', log);
- 
- 	logstate("delivered", ST_DONE);
- 	logstate("failed", ST_ERROR);
- 
- 	logdone(log);
- }
- 
- /*----------------------------------------------------------------------
-  * Log the destinations with the given state.
-  * If any are found, the list is prefixed with the given description.
-  */
- 
- logstate(desc, state)
- char    *desc;
- DSTATE  state;
- {
- 	DEST    *d;
- 	int     count;
- 
- 	count = 0;
- 	for (d = first_dest(); d; d = next_dest(d))
- 	{
- 		if (d->d_state != state)
- 			continue;
- 
- 		if (++count == 1)
- 			(void) fprintf(log, "%s:", desc);
- 		(void) fprintf(log, " %s", d->d_name);
- 		if (d->d_mailbox)
- 			(void) fprintf(log, ":%s", d->d_mailbox);
- 	}
- 	if (count)
- 		(void) fputc('\n', log);
- }
- 
- /*----------------------------------------------------------------------
   * Report any errors to stderr.
   * Return an error count.
--- 693,696 ----
***************
*** 708,726 ****
  
  int
! report_errors()
  {
! 	DEST    *d;
! 	int     count = 0;
  
! 	for (d = first_dest(); d; d = next_dest(d))
! 	{
  		if (d->d_state != ST_ERROR)
  			continue;
  
! 		if (++count == 1)
  		{
! 			error(
! 		 "delivery to the following address(es) failed on host %s:\n",
! 				hostname);
  		}
  
--- 698,734 ----
  
  int
! report_errors(ac, av)
! int	ac;
! char	**av;
  {
! 	DEST	**dv;
! 	int	i, count, errcount;
! 
! 	if ((dv = dest_array(&count)) == NULL)
! 		return 0;
! 
! 	errcount = 0;
! 	for (i = 0; i < count; ++i)
! 	{
! 		DEST    *d;
! 		char	*e;
! 		int	len;
  
! 		d = dv[i];
! 
  		if (d->d_state != ST_ERROR)
  			continue;
  
! 		if (++errcount == 1)
  		{
! 			int	a;
! 
! 			error("delivery error on host %s.\n", hostname);
! 			message("Delivery to %s address%s failed:\n",
! 				ac ? "these" : "this",
! 				ac ? "es" : "");
! 			for (a = 0; a < ac; ++a)
! 				message("\t%s\n", av[a]);
! 			message("Reason(s) for failure:\n");
  		}
  
***************
*** 727,833 ****
  		message("\t\"%s\"", d->d_name);
  		if (d->d_class == CL_MBOX)
! 			message(", mailbox \"%s\"", d->d_mailbox);
! 		message(": %s\n", derrmsg(d->d_error));
! 	}
! 
! 	return count;
! }
! 
! /*----------------------------------------------------------------------
!  * Save log data in the real logfiles.
!  */
! 
! savelogs()
! {
! 	/* If logs weren't kept, forget it. */
! 
! 	if (!log && !errlog)
! 		return;
! 
! 	/* If temporary logs contain anything, append them to real logs. */
! 
! 	if ((log && ftell(log) > 0)
! 	 || (errlog && ftell(errlog) > 0))
! 	{
! 		if (create_lockfile(LOGLOCK) == 0)
! 		{
! 			applog(&log, LOG);
! 			errdone();
! 			applog(&errlog, ERRLOG);
! 			(void) remove_lockfile(LOGLOCK);
! 		}
! 	}
! }
! 
! /*----------------------------------------------------------------------
!  * Append a temporary log file to a real logfile.
!  * We pass a FILE **, so that it can be set to NULL when closed;
!  * this is important, since errlog is used by syserr().
!  * Note:  The logfile is ass_u_med to be locked already!
!  */
! 
! applog(fpp, realfile)
! FILE	**fpp;
! char	*realfile;
! {
! 	FILE	*fp = fpp ? *fpp : NULL;
! 	int	fd, realfd;
! 
! 	/* If log data weren't kept, never mind. */
! 
! 	if (fp == NULL)
! 		return;
! 
! 	/* Flush buffered data. */
! 
! 	(void) fflush(fp);
! 
! 	/* If the file is empty, never mind. */
! 
! 	if (ftell(fp) == 0)
! 	{
! 		(void) fclose(fp);
! 		*fpp = NULL;
! 		return;
! 	}
! 
! 	/* Get an fd and close the stream. */
! 
! 	if ((fd = dup(fileno(fp))) == -1)
! 	{
! 		syserr("can't dup log fd");
! 		(void) fclose(fp);
! 		*fpp = NULL;
! 		return;
! 	}
! 	(void) fclose(fp);
! 	*fpp = NULL;
! 
! 	/*
! 	 * Open the real logfile, creating it if necessary.
! 	 * Note that there is no race condition since the logs are locked.
! 	 */
! 
! #ifdef O_CREAT
! 	realfd = open(realfile, O_WRONLY|O_CREAT, 0666);
! #else
! 	if ((realfd = open(realfile, O_WRONLY)) == -1)
! 		realfd = creat(realfile, 0666);
! #endif
! 	if (realfd == -1)
! 		syserr("can't open %s for writing", logfile);
! 	else
! 	{
! 		/* Append the temporary log to the real log. */
  
! 		(void) lseek(fd, 0L, 0);
! 		(void) lseek(realfd, 0L, 2);
! 		(void) copyfd(fd, realfd);
! 		(void) close(realfd);
  	}
  
! 	/* Close the temporary log. */
  
! 	(void) close(fd);
  }
  
--- 735,752 ----
  		message("\t\"%s\"", d->d_name);
  		if (d->d_class == CL_MBOX)
! 			message(", mailbox \"%s\"", d->d_param);
! 		else if (d->d_class == CL_PROG)
! 			message(", program \"%s\"", d->d_param);
  
! 		e = derrmsg(d);
! 		len = strlen(d->d_name) + strlen(e);
! 		if (d->d_param)
! 			len += strlen(d->d_param);
! 		message(":%s%s\n", (len > 60) ? "\n\t\t" : " ", derrmsg(d));
  	}
  
! 	free((char *) dv);
  
! 	return errcount;
  }
  

Index: mbox.c
***************
*** 1,3 ****
! /* $Header: mbox.c,v 2.3 90/02/06 11:56:42 chip Exp $
   *
   * Finally!  Put the message in the specified mailbox(es).
--- 1,3 ----
! /* $Header: mbox.c,v 2.5 90/02/23 16:35:55 chip Exp $
   *
   * Finally!  Put the message in the specified mailbox(es).
***************
*** 4,7 ****
--- 4,16 ----
   *
   * $Log:	mbox.c,v $
+  * Revision 2.5  90/02/23  16:35:55  chip
+  * \Fix problems determining legality of user references.
+  * 
+  * Revision 2.4  90/02/23  14:16:50  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.3  90/02/06  11:56:42  chip
   * Enforce MBX_MODE regardless of UMASK.
***************
*** 34,37 ****
--- 43,47 ----
   */
  
+ static		prog_one();
  static          mbox_one();
  static  int     mbox_write();
***************
*** 38,63 ****
  
  /*----------------------------------------------------------------------
!  * Deliver mail to all valid destinations.
   */
  
  mbox_deliver()
  {
  	DEST    *d;
  
  	for (d = first_dest(); d; d = next_dest(d))
  	{
! 		switch (d->d_class)
  		{
! 		case CL_USER:
! 		case CL_MBOX:
! 			if (d->d_state == ST_WORKING)
! 				mbox_one(d);
! 			break;
  		}
  	}
  }
  
  /*----------------------------------------------------------------------
!  * Deliver mail to one destination.
   */
  
--- 48,160 ----
  
  /*----------------------------------------------------------------------
!  * Deliver mail to all valid program (pipe) destinations.
!  * Return count of programs to which we tried to write.
!  */
! 
! int
! prog_deliver()
! {
! 	DEST    *d;
! 	int	progcount;
! 
! 	progcount = 0;
! 	for (d = first_dest(); d; d = next_dest(d))
! 	{
! 		if (d->d_state != ST_WORKING)
! 			continue;
! 
! 		if (d->d_class == CL_PROG)
! 		{
! 			prog_one(d);
! 			++progcount;
! 		}
! 	}
! 
! 	return progcount;
! }
! 
! /*----------------------------------------------------------------------
!  * Deliver mail to one program.
!  */
! 
! static
! prog_one(d)
! DEST    *d;
! {
! 	CONTEXT *ct;
! 	char	*av[4];
! 	int	fd;
! 
! 	if (printaddrs)
! 		(void) printf("%s|%s\n", d->d_name, d->d_param);
! 
! 	if (dryrun)
! 	{
! 		d->d_state = ST_DONE;
! 		return;
! 	}
! 
! 	if ((ct = name_context(d->d_name)) == NULL)
! 	{
! 		dest_err(d, E_NSUSER);
! 		return;
! 	}
! 
! 	if (! ok_context(eff_uid, real_uid, real_gid, ct))
! 	{
! 		dest_err(d, E_CTPERM);
! 		return;
! 	}
! 
! 	av[0] = SHELL;
! 	av[1] = "-c";
! 	av[2] = d->d_param;
! 	av[3] = NULL;
! 	if ((fd = ct_openv(ct, av[0], av, O_WRONLY)) == -1)
! 	{
! 		dest_err(d, E_PIPE);
! 		return;
! 	}
! 
! 	(void) lseek(tfd[T_HDR], 0L, 0);
! 	(void) lseek(tfd[T_BODY], 0L, 0);
! 	if (copyfd(tfd[T_HDR], fd) < 0 || copyfd(tfd[T_BODY], fd) < 0)
! 		dest_err(d, E_PIPE);
! 
! 	if (ct_close(fd))
! 		dest_err(d, E_PROG);
! 	else
! 		d->d_state = ST_DONE;
! }
! 
! /*----------------------------------------------------------------------
!  * Deliver mail to all valid mailbox destinations.
!  * Return count of mailboxes to which we tried to write.
   */
  
+ int
  mbox_deliver()
  {
  	DEST    *d;
+ 	int	mboxcount;
  
+ 	mboxcount = 0;
  	for (d = first_dest(); d; d = next_dest(d))
  	{
! 		if (d->d_state != ST_WORKING)
! 			continue;
! 
! 		if (d->d_class == CL_USER || d->d_class == CL_MBOX)
  		{
! 			mbox_one(d);
! 			++mboxcount;
  		}
  	}
+ 
+ 	return mboxcount;
  }
  
  /*----------------------------------------------------------------------
!  * Deliver mail to one mailbox destination.
   */
  
***************
*** 73,77 ****
  		(void) printf("%s", d->d_name);
  		if (d->d_class == CL_MBOX)
! 			(void) printf(":%s", d->d_mailbox);
  		(void) printf("\n");
  	}
--- 170,174 ----
  		(void) printf("%s", d->d_name);
  		if (d->d_class == CL_MBOX)
! 			(void) printf(":%s", d->d_param);
  		(void) printf("\n");
  	}
***************
*** 89,93 ****
  	}
  
! 	if (! ok_context(ct))
  	{
  		dest_err(d, E_CTPERM);
--- 186,190 ----
  	}
  
! 	if (! ok_context(eff_uid, real_uid, real_gid, ct))
  	{
  		dest_err(d, E_CTPERM);
***************
*** 101,105 ****
  			if (become(ct, !boxdelivery) < 0)
  				exit(1);
! 			if (mbox_write(d->d_mailbox, ct, FALSE) < 0)
  				exit(1);
  			exit(0);
--- 198,202 ----
  			if (become(ct, !boxdelivery) < 0)
  				exit(1);
! 			if (mbox_write(d->d_param, ct, FALSE) < 0)
  				exit(1);
  			exit(0);

Index: procs.c
***************
*** 1,3 ****
! /* $Header: procs.c,v 2.4 89/11/01 12:19:05 network Exp $
   *
   * Process management and misc support.
--- 1,3 ----
! /* $Header: procs.c,v 2.6 90/02/23 16:35:59 chip Exp $
   *
   * Process management and misc support.
***************
*** 4,7 ****
--- 4,16 ----
   *
   * $Log:	procs.c,v $
+  * Revision 2.6  90/02/23  16:35:59  chip
+  * \Fix problems determining legality of user references.
+  * 
+  * Revision 2.5  90/02/23  14:16:51  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.4  89/11/01  12:19:05  network
   * Delintify.
***************
*** 46,50 ****
  
  FILE *
! ct_popenv(ct, prog, av, mode)
  CONTEXT *ct;
  char    *prog;
--- 55,59 ----
  
  FILE *
! ct_fopenv(ct, prog, av, mode)
  CONTEXT *ct;
  char    *prog;
***************
*** 52,55 ****
--- 61,116 ----
  char    *mode;
  {
+ 	FILE	*fp;
+ 	int	fd, m;
+ 
+ 	if (mode && mode[0] == 'r' && mode[1] == 0)
+ 		m = O_RDONLY;
+ 	else if (mode && mode[0] == 'w' && mode[1] == 0)
+ 		m = O_WRONLY;
+ 	else
+ 		return NULL;
+ 
+ 	if ((fd = ct_openv(ct, prog, av, m)) == -1)
+ 		return NULL;
+ 
+ 	if ((fp = fdopen(fd, mode)) == NULL)
+ 		(void) ct_close(fd);
+ 
+ 	return fp;
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Close the stream opened by ct_fopen().
+  */
+ 
+ ct_fclose(fp)
+ FILE    *fp;
+ {
+ 	int	fd;
+ 
+ 	if (fp)
+ 	{
+ 		fd = dup(fileno(fp));
+ 		(void) fclose(fp);
+ 	}
+ 	else
+ 		fd = -1;
+ 
+ 	return ct_close(fd);
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Like popen(), but execute the child in a specific context.
+  * Also, the argument list is already a vector.
+  * And return a file descriptor instead of a FILE *.
+  */
+ 
+ int
+ ct_openv(ct, prog, av, mode)
+ CONTEXT *ct;
+ char    *prog;
+ char    **av;
+ int	mode;
+ {
  	char    ch;
  	int     child, parent;
***************
*** 56,68 ****
  	int     pfd[2];
  
! 	if (!ct || !prog || !av || !mode)
  		return NULL;
  
! 	if (mode[0] == 'r' && mode[1] == 0)
  		child = 1, parent = 0;
! 	else if (mode[0] == 'w' && mode[1] == 0)
  		child = 0, parent = 1;
  	else
! 		return NULL;
  
  	/* We can't have more than one child at a time. */
--- 117,132 ----
  	int     pfd[2];
  
! 	if (!ct || !prog || !av)
  		return NULL;
  
! 	if (mode == O_RDONLY)
  		child = 1, parent = 0;
! 	else if (mode == O_WRONLY)
  		child = 0, parent = 1;
  	else
! 	{
! 		error("in ct_open: invalid mode");
! 		return -1;
! 	}
  
  	/* We can't have more than one child at a time. */
***************
*** 70,75 ****
  	if (child_pid >= 0)
  	{
! 		error("in ct_popen: a process is already open\n");
! 		return NULL;
  	}
  
--- 134,139 ----
  	if (child_pid >= 0)
  	{
! 		error("in ct_open: a process is already open");
! 		return -1;
  	}
  
***************
*** 76,84 ****
  	/* Make a stab at predicting uid-related failure. */
  
! 	if (! ok_context(ct))
  	{
! 		error("in ct_popen: no permissions to become %s\n",
! 		      ct->ct_name);
! 		return NULL;
  	}
  
--- 140,147 ----
  	/* Make a stab at predicting uid-related failure. */
  
! 	if (! ok_context(eff_uid, real_uid, real_gid, ct))
  	{
! 		error("in ct_open: no permissions to become %s", ct->ct_name);
! 		return -1;
  	}
  
***************
*** 88,92 ****
  	{
  		syserr("can't create a pipe");
! 		return NULL;
  	}
  
--- 151,155 ----
  	{
  		syserr("can't create a pipe");
! 		return -1;
  	}
  
***************
*** 97,101 ****
  		int a;
  
! 		message("Spawning");
  		for (a = 0; av[a]; ++a)
  			message(" %s", av[a]);
--- 160,164 ----
  		int a;
  
! 		message("%s: spawning", progname);
  		for (a = 0; av[a]; ++a)
  			message(" %s", av[a]);
***************
*** 161,180 ****
  		(void) close(pfd[1]);
  		(void) await_child();
! 		return NULL;
  	}
  
  	(void) close(pfd[child]);
! 	return fdopen(pfd[parent], mode);
  }
  
  /*----------------------------------------------------------------------
!  * Close the stream opened by ct_popen().
   */
  
! ct_pclose(fp)
! FILE    *fp;
  {
! 	if (fp)
! 		(void) fclose(fp);
  	return await_child();
  }
--- 224,243 ----
  		(void) close(pfd[1]);
  		(void) await_child();
! 		return -1;
  	}
  
  	(void) close(pfd[child]);
! 	return pfd[parent];
  }
  
  /*----------------------------------------------------------------------
!  * Close the file descriptor opened by ct_open().
   */
  
! ct_close(fd)
! int	fd;
  {
! 	if (fd != -1)
! 		(void) close(fd);
  	return await_child();
  }
***************
*** 298,305 ****
  	if (st & 0xFF)
  	{
! 		error("child process died%s due to signal %d.\n",
  			((st & 0x80) ? " and dumped core" : ""),
  			(st & 0x7F));
- 
  		return -1;
  	}
--- 361,367 ----
  	if (st & 0xFF)
  	{
! 		error("child process died%s due to signal %d.",
  			((st & 0x80) ? " and dumped core" : ""),
  			(st & 0x7F));
  		return -1;
  	}
***************
*** 307,312 ****
  	if (verbose)
  	{
! 		message("child process exited with status %d.\n",
! 			(st >> 8) & 0xFF);
  	}
  
--- 369,374 ----
  	if (verbose)
  	{
! 		message("%s: child process exited with status %d.\n",
! 			progname, (st >> 8) & 0xFF);
  	}
  

Index: subs.c
***************
*** 1,3 ****
! /* $Header: subs.c,v 2.4 90/02/06 11:56:46 chip Exp $
   *
   * Miscellaneous subroutines.
--- 1,3 ----
! /* $Header: subs.c,v 2.6 90/03/06 12:21:17 chip Exp $
   *
   * Miscellaneous subroutines.
***************
*** 4,7 ****
--- 4,18 ----
   *
   * $Log:	subs.c,v $
+  * Revision 2.6  90/03/06  12:21:17  chip
+  * Move logging into log.c and address parsing into addr.c.
+  * New: error delivery file for messages that fail.
+  * Major rearrangement of delivery file code.
+  * 
+  * Revision 2.5  90/02/23  14:16:56  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.4  90/02/06  11:56:46  chip
   * Enforce MBX_MODE regardless of UMASK.
***************
*** 286,307 ****
  
  	return path;
- }
- 
- /*----------------------------------------------------------------------
-  * Check an address for validity.
-  */
- 
- valid_address(addr)
- char    *addr;
- {
- 	char    *p;
- 	static char sanitize[] = SANITIZE;
- 
- 	for (p = addr; *p; ++p)
- 	{
- 		if (strchr(sanitize, *p))
- 			return FALSE;
- 	}
- 
- 	return TRUE;
  }
--- 297,299 ----

Index: sysdep.c
***************
*** 1,3 ****
! /* $Header: sysdep.c,v 2.6 90/02/06 11:56:43 chip Exp $
   *
   * Routines which are (or might well be) system-dependant.
--- 1,3 ----
! /* $Header: sysdep.c,v 2.8 90/03/06 12:21:16 chip Exp $
   *
   * Routines which are (or might well be) system-dependant.
***************
*** 6,9 ****
--- 6,20 ----
   *
   * $Log:	sysdep.c,v $
+  * Revision 2.8  90/03/06  12:21:16  chip
+  * Move logging into log.c and address parsing into addr.c.
+  * New: error delivery file for messages that fail.
+  * Major rearrangement of delivery file code.
+  * 
+  * Revision 2.7  90/02/23  14:16:52  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.6  90/02/06  11:56:43  chip
   * Enforce MBX_MODE regardless of UMASK.
***************
*** 33,37 ****
  #include "deliver.h"
  #include <errno.h>
- #include <time.h>
  #ifdef HAS_STDARG
  #include <stdarg.h>
--- 44,47 ----
***************
*** 178,368 ****
  	else
  		(void) fprintf(fp, ": unknown system error %d\n", e);
- }
- 
- /*----------------------------------------------------------------------
-  * Record any interesting information in the error log file.
-  */
- 
- errinfo()
- {
- 	if (!errlog)
- 		return;
- 
- 	/* Log undelivered mail. */
- 
- 	errundel();
- 
- 	/* If any errors have been logged, record the failed header. */
- 
- 	if (ftell(errlog) > 0)
- 		errheader();
- }
- 
- /*----------------------------------------------------------------------
-  * Log undelivered mail.
-  *
-  * Note that this algorithm assumes that delivery to the MBX_UNDEL mailbox
-  * is always worth reporting.
-  */
- 
- errundel()
- {
- 	DEST    *d;
- 
- 	if (!errlog)
- 		return;
- 
- 	for (d = first_dest(); d; d = next_dest(d))
- 	{
- 		if (d->d_state == ST_DONE
- 		 && d->d_class == CL_MBOX
- 		 && strcmp(d->d_mailbox, MBX_UNDEL) == 0)
- 		{
- 			CONTEXT *ct;
- 			char    *home;
- 
- 			if ((ct = name_context(d->d_name)) != NULL)
- 				home = ct->ct_home;
- 			else
- 				home = "~";     /* should never happen */
- 
- 			errstart();
- 			(void) fprintf(errlog,
- 			    "Undelivered mail for %s put in %s/%s\n",
- 			    d->d_name, home, MBX_UNDEL);
- 		}
- 	}
- }
- 
- /*----------------------------------------------------------------------
-  * Log the message header.
-  */
- 
- errheader()
- {
- 	FILE    *hfp;
- 	int     hfd;
- 
- 	if (!errlog)
- 		return;
- 
- 	/* Copy the failed message's header. */
- 
- 	hfd = dup(tfd[T_HDR]);
- 	hfp = (hfd < 0) ? NULL : fdopen(hfd, "r");
- 	if (hfp == NULL)
- 	{
- 		(void) fprintf(errlog, "%s: can't open header file %s\n",
- 					progname, tfile[T_HDR]);
- 	}
- 	else
- 	{
- 		int     c, oc;
- 
- 		(void) fprintf(errlog, "+ Header:\n");
- 
- 		(void) fseek(hfp, 0L, 0);
- 		oc = '\n';
- 		while ((c = getc(hfp)) != EOF)
- 		{
- 			if (oc != '\n' || c != '\n')
- 			{
- 				if (oc == '\n')
- 					(void) fputs("| ", errlog);
- 				(void) putc(c, errlog);
- 			}
- 			oc = c;
- 		}
- 
- 		(void) fclose(hfp);
- 	}
- }
- 
- /*----------------------------------------------------------------------
-  * Record a time stamp in the error log file.
-  */
- 
- errstart()
- {
- 	/* If we've already written a time stamp, don't do it again. */
- 
- 	if (!errlog || ftell(errlog) > 0)
- 		return;
- 
- 	/* Write a time stamp and various useful info. */
- 
- 	logstart(errlog);
- 	(void) fprintf(errlog, "process %d", getpid());
- 	if (rec_parent > 0)
- 		(void) fprintf(errlog, ", parent %d", rec_parent);
- 	(void) fprintf(errlog, ": %s %s\n", progname, version);
- }
- 
- /*----------------------------------------------------------------------
-  * Record the end of this process's error log entry.
-  */
- 
- errdone()
- {
- 	/* If we never wrote to the error log file, do nothing. */
- 
- 	if (!errlog || ftell(errlog) == 0)
- 		return;
- 
- 	/* Write a simple closing line for the error log entry. */
- 
- 	(void) fprintf(errlog, "process %d", getpid());
- 	if (rec_parent > 0)
- 		(void) fprintf(errlog, ", parent %d", rec_parent);
- 	(void) fprintf(errlog, ": exit\n");
- 
- 	logdone(errlog);
- }
- 
- /*----------------------------------------------------------------------
-  * Start a log entry.
-  * Various useful info goes here -- especially a timestamp.
-  */
- 
- logstart(fp)
- FILE    *fp;
- {
- 	struct tm *lt;
- 	time_t  now;
- 	static char month[12][4] = {
- 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- 	};
- 
- 	(void) time(&now);
- 	lt = localtime(&now);
- 
- 	(void) fputc('\n', fp);
- 	if (rec_level)
- 		(void) fprintf(fp, "[%d]", rec_level);
- 	else
- 		(void) fputs("---", fp);
- 	(void) fputs("------------------------ ", fp);
- 	(void) fprintf(fp, "%d %s %d, %02d:%02d:%02d %s\n",
- 			lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900,
- 			lt->tm_hour, lt->tm_min, lt->tm_sec,
- #ifdef USG
- 			tzname[lt->tm_isdst ? 1 : 0]
- #else
- 			lt->tm_zone
- #endif
- 			);
- }
- 
- /*----------------------------------------------------------------------
-  * Write a concluding marker to the given logfile.
-  * This marker separates instances of Deliver at recursion level zero.
-  */
- 
- logdone(fp)
- FILE	*fp;
- {
- 	if (rec_level == 0)
- 		(void) fputs("===========================\n\n", fp);
  }
  
--- 188,191 ----

Index: uucp.c
***************
*** 1,3 ****
! /* $Header: uucp.c,v 2.3 89/12/19 16:26:41 network Exp $
   *
   * Handle mail destined for other hosts via UUCP.
--- 1,3 ----
! /* $Header: uucp.c,v 2.4 90/02/23 14:16:54 chip Exp $
   *
   * Handle mail destined for other hosts via UUCP.
***************
*** 6,9 ****
--- 6,15 ----
   *
   * $Log:	uucp.c,v $
+  * Revision 2.4  90/02/23  14:16:54  chip
+  * Support "#!" in delivery files.
+  * Support "user|program" and "user?error" from delivery files.
+  * Improve debugging and error message formatting.
+  * Rearrange code for clarity.
+  * 
   * Revision 2.3  89/12/19  16:26:41  network
   * Execute UUCP in real, not effective, context.
***************
*** 31,37 ****
--- 37,45 ----
  /*----------------------------------------------------------------------
   * Send mail to UUCP addresses (if any).
+  * Return count of UUCP addresses for which delivery was attempted.
   * This is a simple implementation: invoke uux once per address.
   */
  
+ int
  uucp_deliver()
  {
***************
*** 38,41 ****
--- 46,50 ----
  	DEST    *d;
  	char    *uux;
+ 	int	uucpcount;
  	static char uux1[] = "/bin/uux";
  	static char uux2[] = "/usr/bin/uux";
***************
*** 48,54 ****
  	{
  		error("can't find uux!?\n");
! 		return;
  	}
  
  	for (d = first_dest(); d; d = next_dest(d))
  	{
--- 57,64 ----
  	{
  		error("can't find uux!?\n");
! 		return -1;
  	}
  
+ 	uucpcount = 0;
  	for (d = first_dest(); d; d = next_dest(d))
  	{
***************
*** 62,65 ****
--- 72,77 ----
  			continue;
  
+ 		++uucpcount;
+ 
  		if (printaddrs)
  			(void) printf("%s\n", d->d_name);
***************
*** 82,92 ****
  		av[3] = who;
  		av[4] = NULL;
! 		if ((uux_fp = ct_popenv(real_ct, uux, av, "w")) == NULL)
  			continue;
  
  		if (uucp_copy(uux_fp) < 0)
! 			dest_err(d, E_UUX);
  
! 		if (ct_pclose(uux_fp))
  		{
  			/* "No such host" overrides piping problems. */
--- 94,104 ----
  		av[3] = who;
  		av[4] = NULL;
! 		if ((uux_fp = ct_fopenv(real_ct, uux, av, "w")) == NULL)
  			continue;
  
  		if (uucp_copy(uux_fp) < 0)
! 			dest_err(d, E_PIPE);
  
! 		if (ct_fclose(uux_fp))
  		{
  			/* "No such host" overrides piping problems. */
***************
*** 96,99 ****
--- 108,113 ----
  			d->d_state = ST_DONE;
  	}
+ 
+ 	return uucpcount;
  }
  
-- 
Chip Salzenberg at ComDev/TCT   <chip%tct@ateng.com>, <uunet!ateng!tct!chip>
          "The Usenet, in a very real sense, does not exist."

kv56962@tut.fi (V{{r{nen Kari) (03/09/90)

Would someone, please, tell me what Deliver is and what it does.

--
	SO LONG AND THANKS FOR ALL THE FISH	(The dolphins)
Kari Vaaranen                                 Tampere University of Technology
Majakkakatu 30,                                                 kv56962@tut.fi
SF-33410 Tampere, FINLAND             (These opinions are mine and mine ONLY!)