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); } /*