[comp.mail.sendmail] broken alias error handling patch

fletcher@cs.utexas.edu (Fletcher Mattox) (10/14/89)

A while back I complained that sendmail does not do much in
the way of error handling when mail to a broken alias
arrives via SMTP. (A broken alias is any alias which contains
at least one local recipient which is not deliverable.)
In particular, sendmail does not deliver to any of the valid
addresses on the list, nor does it notify the "owner-"
of the error.

Since all of our aliases are served from a central "alias
server" via SMTP, we need this functionality to detect
errors in our (huge) alias file.  Here's what I did to 5.59.
It's not terribly aesthetic, but it works.


*** src.old/srvrsmtp.c	Wed Nov 16 11:25:42 1988
--- src/srvrsmtp.c	Sat Oct 14 08:17:52 1989
***************
*** 98,103
  char	*WizWord;			/* the wizard word to compare against */
  bool	InChild = FALSE;		/* true if running in a subprocess */
  bool	OneXact = FALSE;		/* one xaction only this run */
  
  #define EX_QUIT		22		/* special code for QUIT command */
  

--- 98,104 -----
  char	*WizWord;			/* the wizard word to compare against */
  bool	InChild = FALSE;		/* true if running in a subprocess */
  bool	OneXact = FALSE;		/* one xaction only this run */
+ bool	InRCPT = FALSE;			/* are we in RCPT To: command? */
  
  #define EX_QUIT		22		/* special code for QUIT command */
  
***************
*** 108,113
  	char *cmd;
  	extern char *skipword();
  	bool hasmail;			/* mail command received */
  	auto ADDRESS *vrfyqueue;
  	ADDRESS *a;
  	char *sendinghost;

--- 109,115 -----
  	char *cmd;
  	extern char *skipword();
  	bool hasmail;			/* mail command received */
+ 	bool aliaserror;		/* bad address in the alias file? */
  	auto ADDRESS *vrfyqueue;
  	ADDRESS *a;
  	char *sendinghost;
***************
*** 118,123
  	extern bool iswiz();
  	extern char *arpadate();
  	extern char *macvalue();
  	extern ADDRESS *recipient();
  	extern ENVELOPE BlankEnvelope;
  	extern ENVELOPE *newenvelope();

--- 120,126 -----
  	extern bool iswiz();
  	extern char *arpadate();
  	extern char *macvalue();
+ 	extern char *aliaslookup();
  	extern ADDRESS *recipient();
  	extern ENVELOPE BlankEnvelope;
  	extern ENVELOPE *newenvelope();
***************
*** 122,128
  	extern ENVELOPE BlankEnvelope;
  	extern ENVELOPE *newenvelope();
  
! 	hasmail = FALSE;
  	if (OutChannel != stdout)
  	{
  		/* arrange for debugging output to go to remote host */

--- 125,131 -----
  	extern ENVELOPE BlankEnvelope;
  	extern ENVELOPE *newenvelope();
  
! 	hasmail = aliaserror = FALSE;
  	if (OutChannel != stdout)
  	{
  		/* arrange for debugging output to go to remote host */
***************
*** 279,284
  			if (a == NULL)
  				break;
  			a->q_flags |= QPRIMARY;
  			a = recipient(a, &CurEnv->e_sendqueue);
  			if (Errors != 0)
  				break;

--- 282,289 -----
  			if (a == NULL)
  				break;
  			a->q_flags |= QPRIMARY;
+ 
+ 			InRCPT = TRUE;
  			a = recipient(a, &CurEnv->e_sendqueue);
  			InRCPT = FALSE;
  
***************
*** 280,287
  				break;
  			a->q_flags |= QPRIMARY;
  			a = recipient(a, &CurEnv->e_sendqueue);
! 			if (Errors != 0)
! 				break;
  
  			/* no errors during parsing, but might be a duplicate */
  			CurEnv->e_to = p;

--- 285,291 -----
  
  			InRCPT = TRUE;
  			a = recipient(a, &CurEnv->e_sendqueue);
! 			InRCPT = FALSE;
  
  			/*
  			 * The gratuitous twiddling of the fatal error
***************
*** 283,289
  			if (Errors != 0)
  				break;
  
! 			/* no errors during parsing, but might be a duplicate */
  			CurEnv->e_to = p;
  			if (!bitset(QBADADDR, a->q_flags))
  				message("250", "Recipient ok");

--- 287,299 -----
  			a = recipient(a, &CurEnv->e_sendqueue);
  			InRCPT = FALSE;
  
! 			/*
! 			 * The gratuitous twiddling of the fatal error
! 			 * bit below is to detect bad addresses in the alias
! 			 * file and to notify local owner- addresses while
! 			 * trying not to send the remote user a (duplicate)
! 			 * error if his mailer is capable of that.
! 			 */
  			CurEnv->e_to = p;
  			if (aliaslookup(a->q_user))
  			{
***************
*** 285,291
  
  			/* no errors during parsing, but might be a duplicate */
  			CurEnv->e_to = p;
! 			if (!bitset(QBADADDR, a->q_flags))
  				message("250", "Recipient ok");
  			else
  			{

--- 295,315 -----
  			 * error if his mailer is capable of that.
  			 */
  			CurEnv->e_to = p;
! 			if (aliaslookup(a->q_user))
! 			{
! 				/*
! 				 * If the rcpt to: line is in the alias file
! 				 * tell the sender it's ok.  It may expand to
! 				 * an invalid address, but we lie to the sender
! 				 * and say it's ok.  This permits us to honor
! 				 * the owner- alias and to deliver to valid
! 				 * addressees on the alias list, if any.
! 				 *
! 				 * If there was an error, remember it
! 				 * since the error bit can get cleared
! 				 * on the next rcpt to: and since we
! 				 * want to report the error later on.
! 				 */
  				message("250", "Recipient ok");
  				if (bitset(EF_FATALERRS, CurEnv->e_flags))
  					aliaserror = TRUE;
***************
*** 287,292
  			CurEnv->e_to = p;
  			if (!bitset(QBADADDR, a->q_flags))
  				message("250", "Recipient ok");
  			else
  			{
  				/* punt -- should keep message in ADDRESS.... */

--- 311,319 -----
  				 * want to report the error later on.
  				 */
  				message("250", "Recipient ok");
+ 				if (bitset(EF_FATALERRS, CurEnv->e_flags))
+ 					aliaserror = TRUE;
+ 			}
  			else
  			{
  				if (!bitset(QBADADDR, a->q_flags))
***************
*** 289,296
  				message("250", "Recipient ok");
  			else
  			{
! 				/* punt -- should keep message in ADDRESS.... */
! 				message("550", "Addressee unknown");
  			}
  			CurEnv->e_to = NULL;
  			break;

--- 316,333 -----
  			}
  			else
  			{
! 				if (!bitset(QBADADDR, a->q_flags))
! 					message("250", "Recipient ok");
! 				else
! 				{
! 					/*
! 					 * This will cause the sending mailer
! 					 * to notify the user.  We clear the
! 					 * error bit so we don't notify him.
! 					 */
! 					message("550", "Addressee unknown");
! 					CurEnv->e_flags &= ~EF_FATALERRS;
! 				}
  			}
  			CurEnv->e_to = NULL;
  			break;
***************
*** 318,337
  
  			/*
  			**  Arrange to send to everyone.
! 			**	If sending to multiple people, mail back
! 			**		errors rather than reporting directly.
! 			**	In any case, don't mail back errors for
! 			**		anything that has happened up to
! 			**		now (the other end will do this).
! 			**	Truncate our transcript -- the mail has gotten
! 			**		to us successfully, and if we have
! 			**		to mail this back, it will be easier
! 			**		on the reader.
! 			**	Then send to everyone.
! 			**	Finally give a reply code.  If an error has
! 			**		already been given, don't mail a
! 			**		message back.
! 			**	We goose error returns by clearing error bit.
  			*/
  
  			SmtpPhase = "delivery";

--- 355,370 -----
  
  			/*
  			**  Arrange to send to everyone.
! 			**
! 			**  A note on error handling:
! 			**	Originally, sendmail did not mail back errors
! 			**	which ocurred during address verification.
! 			**	This code does.
! 			**
! 			**	Since we returned a 250 in the Rcpt To:
! 			**	for an address which contained potentially
! 			**	bad addresses, we must honor EF_FATALERRS 
! 			**	and mail back an error message.
  			*/
  
  			SmtpPhase = "delivery";
***************
*** 340,347
  				HoldErrs = TRUE;
  				ErrorMode = EM_MAIL;
  			}
- 			CurEnv->e_flags &= ~EF_FATALERRS;
- 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
  
  			/* send to all recipients */
  			sendall(CurEnv, SM_DEFAULT);

--- 373,378 -----
  				HoldErrs = TRUE;
  				ErrorMode = EM_MAIL;
  			}
  
  			/* send to all recipients */
  			sendall(CurEnv, SM_DEFAULT);
***************
*** 353,360
  			/* issue success if appropriate and reset */
  			if (Errors == 0 || HoldErrs)
  				message("250", "Ok");
! 			else
! 				CurEnv->e_flags &= ~EF_FATALERRS;
  
  			/* if in a child, pop back to our parent */
  			if (InChild)

--- 384,396 -----
  			/* issue success if appropriate and reset */
  			if (Errors == 0 || HoldErrs)
  				message("250", "Ok");
! 
! 			/*
! 			 * Was there an error expanding the alias?
! 			 * If so, make sure we mail it back.
! 			 */
! 			 if (aliaserror)
! 				CurEnv->e_flags |= EF_FATALERRS;
  
  			/* if in a child, pop back to our parent */
  			if (InChild)
*** src.old/recipient.c	Wed Nov 16 11:25:44 1988
--- src/recipient.c	Sat Oct 14 08:17:54 1989
***************
*** 300,305
  		{
  			register struct passwd *pw;
  			extern struct passwd *finduser();
  
  			/* warning -- finduser may trash buf */
  			pw = finduser(buf);

--- 300,306 -----
  		{
  			register struct passwd *pw;
  			extern struct passwd *finduser();
+ 			extern bool InRCPT;
  
  			/* warning -- finduser may trash buf */
  			pw = finduser(buf);
***************
*** 306,312
  			if (pw == NULL)
  			{
  				a->q_flags |= QBADADDR;
! 				giveresponse(EX_NOUSER, m, CurEnv);
  			}
  			else
  			{

--- 307,328 -----
  			if (pw == NULL)
  			{
  				a->q_flags |= QBADADDR;
! 				/*
! 				 * postpone response if talking SMTP,
! 				 * but flag a fatal error so we can
! 				 * call savemail() later on.
! 				 */
! 				if (InRCPT)
! 				{
! 					CurEnv->e_flags |= EF_FATALERRS;
! 					if (LogLevel > 2)
! 						logdelivery("User unkown");
! 					if (CurEnv->e_xfp != NULL)
! 						fprintf(CurEnv->e_xfp,
! 						"%s: User unknown\n", buf);
! 				}
! 				else
! 					giveresponse(EX_NOUSER, m, CurEnv);
  			}
  			else
  			{
***************
*** 371,376
  	if ((pw = getpwnam(name)) != NULL)
  		return (pw);
  
  	/* search for a matching full name instead */
  	for (p = name; *p != '\0'; p++)
  	{

--- 387,394 -----
  	if ((pw = getpwnam(name)) != NULL)
  		return (pw);
  
+ #ifdef notdef
+ 
  	/* search for a matching full name instead */
  	for (p = name; *p != '\0'; p++)
  	{
***************
*** 389,394
  			return (pw);
  		}
  	}
  	return (NULL);
  }
  /*

--- 407,415 -----
  			return (pw);
  		}
  	}
+ 
+ #endif notdef
+ 
  	return (NULL);
  }
  /*