122705Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362525Sbostic * Copyright (c) 1988, 1993 462525Sbostic * The Regents of the University of California. All rights reserved. 533729Sbostic * 642826Sbostic * %sccs.include.redist.c% 733729Sbostic */ 822705Sdist 922705Sdist #ifndef lint 10*63753Seric static char sccsid[] = "@(#)err.c 8.2 (Berkeley) 07/11/93"; 1133729Sbostic #endif /* not lint */ 1222705Sdist 133311Seric # include "sendmail.h" 1424943Seric # include <errno.h> 1525526Smiriam # include <netdb.h> 16295Seric 17295Seric /* 181514Seric ** SYSERR -- Print error message. 19295Seric ** 20295Seric ** Prints an error message via printf to the diagnostic 21295Seric ** output. If LOG is defined, it logs it also. 22295Seric ** 2358690Seric ** If the first character of the syserr message is `!' it will 2458690Seric ** log this as an ALERT message and exit immediately. This can 2558690Seric ** leave queue files in an indeterminate state, so it should not 2658690Seric ** be used lightly. 2758690Seric ** 28295Seric ** Parameters: 29295Seric ** f -- the format string 30295Seric ** a, b, c, d, e -- parameters 31295Seric ** 32295Seric ** Returns: 334084Seric ** none 347762Seric ** Through TopFrame if QuickAbort is set. 35295Seric ** 36295Seric ** Side Effects: 371514Seric ** increments Errors. 381514Seric ** sets ExitStat. 39295Seric */ 40295Seric 414084Seric # ifdef lint 424084Seric int sys_nerr; 434084Seric char *sys_errlist[]; 444084Seric # endif lint 4510147Seric char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 464084Seric 4746928Sbostic static void fmtmsg(); 4846928Sbostic 4958824Seric void 50295Seric /*VARARGS1*/ 5157642Seric #ifdef __STDC__ 5260094Seric syserr(const char *fmt, ...) 5357642Seric #else 5457642Seric syserr(fmt, va_alist) 5560094Seric const char *fmt; 5657642Seric va_dcl 5757642Seric #endif 58295Seric { 5916901Seric register char *p; 6016901Seric int olderrno = errno; 6158690Seric bool panic; 6256852Seric VA_LOCAL_DECL 63295Seric 6458690Seric panic = *fmt == '!'; 6558690Seric if (panic) 6658690Seric fmt++; 6758690Seric 687525Seric /* format and output the error message */ 6916901Seric if (olderrno == 0) 7058151Seric p = "554"; 717957Seric else 7258151Seric p = "451"; 7356852Seric VA_START(fmt); 7456852Seric fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 7556852Seric VA_END; 769389Seric puterrmsg(MsgBuf); 774063Seric 78295Seric /* determine exit status if not already set */ 79295Seric if (ExitStat == EX_OK) 80295Seric { 8116901Seric if (olderrno == 0) 82295Seric ExitStat = EX_SOFTWARE; 83295Seric else 841598Seric ExitStat = EX_OSERR; 85295Seric } 86295Seric 87295Seric # ifdef LOG 887674Seric if (LogLevel > 0) 8958690Seric syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", 9025277Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 9125277Seric &MsgBuf[4]); 9256795Seric # endif /* LOG */ 9358690Seric if (panic) 9459156Seric { 9559156Seric #ifdef XLA 9659156Seric xla_all_end(); 9759156Seric #endif 9858690Seric exit(EX_OSERR); 9959156Seric } 100295Seric errno = 0; 1017762Seric if (QuickAbort) 1027762Seric longjmp(TopFrame, 2); 103295Seric } 104295Seric /* 105295Seric ** USRERR -- Signal user error. 106295Seric ** 107295Seric ** This is much like syserr except it is for user errors. 108295Seric ** 109295Seric ** Parameters: 110295Seric ** fmt, a, b, c, d -- printf strings 111295Seric ** 112295Seric ** Returns: 1134084Seric ** none 1147762Seric ** Through TopFrame if QuickAbort is set. 115295Seric ** 116295Seric ** Side Effects: 1171514Seric ** increments Errors. 118295Seric */ 119295Seric 120295Seric /*VARARGS1*/ 12158824Seric void 12257642Seric #ifdef __STDC__ 12360094Seric usrerr(const char *fmt, ...) 12457642Seric #else 12557642Seric usrerr(fmt, va_alist) 12660094Seric const char *fmt; 12757642Seric va_dcl 12857642Seric #endif 129295Seric { 13056852Seric VA_LOCAL_DECL 131295Seric extern char SuprErrs; 13216901Seric extern int errno; 133295Seric 134295Seric if (SuprErrs) 1354084Seric return; 136295Seric 13756852Seric VA_START(fmt); 13858524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 13956852Seric VA_END; 1409389Seric puterrmsg(MsgBuf); 1418239Seric 14251951Seric # ifdef LOG 14358020Seric if (LogLevel > 3 && LogUsrErrs) 14451951Seric syslog(LOG_NOTICE, "%s: %s", 14551951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 14651951Seric &MsgBuf[4]); 14756795Seric # endif /* LOG */ 14851951Seric 1497762Seric if (QuickAbort) 1507762Seric longjmp(TopFrame, 1); 1514063Seric } 1524063Seric /* 1534063Seric ** MESSAGE -- print message (not necessarily an error) 1544063Seric ** 1554063Seric ** Parameters: 15659581Seric ** msg -- the message (printf fmt) -- it can begin with 15759581Seric ** an SMTP reply code. If not, 050 is assumed. 1584063Seric ** a, b, c, d, e -- printf arguments 1594063Seric ** 1604063Seric ** Returns: 1614063Seric ** none 1624063Seric ** 1634063Seric ** Side Effects: 1644063Seric ** none. 1654063Seric */ 1664063Seric 1674084Seric /*VARARGS2*/ 16858826Seric void 16957642Seric #ifdef __STDC__ 17060094Seric message(const char *msg, ...) 17157642Seric #else 17258151Seric message(msg, va_alist) 17360094Seric const char *msg; 17457642Seric va_dcl 17557642Seric #endif 1764063Seric { 17756852Seric VA_LOCAL_DECL 17856852Seric 1794711Seric errno = 0; 18056852Seric VA_START(msg); 18158151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 18256852Seric VA_END; 183*63753Seric putoutmsg(MsgBuf, FALSE); 1847613Seric } 1857613Seric /* 1868239Seric ** NMESSAGE -- print message (not necessarily an error) 1878239Seric ** 1888239Seric ** Just like "message" except it never puts the to... tag on. 1898239Seric ** 1908239Seric ** Parameters: 1918239Seric ** num -- the default ARPANET error number (in ascii) 1928239Seric ** msg -- the message (printf fmt) -- if it begins 19324943Seric ** with three digits, this number overrides num. 1948239Seric ** a, b, c, d, e -- printf arguments 1958239Seric ** 1968239Seric ** Returns: 1978239Seric ** none 1988239Seric ** 1998239Seric ** Side Effects: 2008239Seric ** none. 2018239Seric */ 2028239Seric 2038239Seric /*VARARGS2*/ 20458826Seric void 20557642Seric #ifdef __STDC__ 20660094Seric nmessage(const char *msg, ...) 20757642Seric #else 20858151Seric nmessage(msg, va_alist) 20960094Seric const char *msg; 21057642Seric va_dcl 21157642Seric #endif 2128239Seric { 21356852Seric VA_LOCAL_DECL 21456852Seric 2158239Seric errno = 0; 21656852Seric VA_START(msg); 21758151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 21856852Seric VA_END; 219*63753Seric putoutmsg(MsgBuf, FALSE); 2208239Seric } 2218239Seric /* 222*63753Seric ** PUTOUTMSG -- output error message to transcript and channel 2237613Seric ** 2247613Seric ** Parameters: 2257613Seric ** msg -- message to output (in SMTP format). 2269108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2279108Seric ** our output channel. 2287613Seric ** 2297613Seric ** Returns: 2307613Seric ** none. 2317613Seric ** 2327613Seric ** Side Effects: 2337613Seric ** Outputs msg to the transcript. 2347613Seric ** If appropriate, outputs it to the channel. 2357613Seric ** Deletes SMTP reply code number as appropriate. 2367613Seric */ 2374711Seric 238*63753Seric putoutmsg(msg, holdmsg) 2397613Seric char *msg; 2409108Seric bool holdmsg; 2417613Seric { 24214900Seric /* output to transcript if serious */ 24314900Seric if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5')) 24414900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2454711Seric 2464711Seric /* output to channel if appropriate */ 24760421Seric if (holdmsg || (!Verbose && msg[0] == '0')) 24860421Seric return; 24960421Seric 25060421Seric (void) fflush(stdout); 25160421Seric if (OpMode == MD_SMTP) 25260421Seric fprintf(OutChannel, "%s\r\n", msg); 25360421Seric else 25460421Seric fprintf(OutChannel, "%s\n", &msg[4]); 255*63753Seric if (TrafficLogFile != NULL) 256*63753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 257*63753Seric OpMode == MD_SMTP ? msg : &msg[4]); 25860421Seric if (msg[3] == ' ') 25960421Seric (void) fflush(OutChannel); 26060421Seric if (!ferror(OutChannel)) 26160421Seric return; 26260421Seric 26360421Seric /* error on output -- if reporting lost channel, just ignore it */ 26460421Seric if (feof(InChannel) || ferror(InChannel)) 26560421Seric return; 26660421Seric 26760421Seric /* can't call syserr, 'cause we are using MsgBuf */ 26860421Seric HoldErrs = TRUE; 26960283Seric #ifdef LOG 27060421Seric if (LogLevel > 0) 27160421Seric syslog(LOG_CRIT, 272*63753Seric "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"", 27360421Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 27460421Seric CurHostName, msg); 27560283Seric #endif 2769389Seric } 2779389Seric /* 278*63753Seric ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 2799389Seric ** 2809389Seric ** Parameters: 2819389Seric ** msg -- the message to output. 2829389Seric ** 2839389Seric ** Returns: 2849389Seric ** none. 2859389Seric ** 2869389Seric ** Side Effects: 2879389Seric ** Sets the fatal error bit in the envelope as appropriate. 2889389Seric */ 2898239Seric 2909389Seric puterrmsg(msg) 2919389Seric char *msg; 2929389Seric { 2939389Seric /* output the message as usual */ 294*63753Seric putoutmsg(msg, HoldErrs); 2959389Seric 2969389Seric /* signal the error */ 2979389Seric Errors++; 2989389Seric if (msg[0] == '5') 2999336Seric CurEnv->e_flags |= EF_FATALERRS; 3004711Seric } 3014711Seric /* 3024711Seric ** FMTMSG -- format a message into buffer. 3034711Seric ** 3044711Seric ** Parameters: 3054711Seric ** eb -- error buffer to get result. 3064711Seric ** to -- the recipient tag for this message. 3074711Seric ** num -- arpanet error number. 30816901Seric ** en -- the error number to display. 3094711Seric ** fmt -- format of string. 3104711Seric ** a, b, c, d, e -- arguments. 3114711Seric ** 3124711Seric ** Returns: 3134711Seric ** none. 3144711Seric ** 3154711Seric ** Side Effects: 3164711Seric ** none. 3174711Seric */ 3184063Seric 31946928Sbostic static void 32056852Seric fmtmsg(eb, to, num, eno, fmt, ap) 3214711Seric register char *eb; 3224711Seric char *to; 3234711Seric char *num; 32416904Seric int eno; 3254711Seric char *fmt; 32656852Seric va_list ap; 3274711Seric { 3284711Seric char del; 32959596Seric char *meb; 3304711Seric 3314711Seric /* output the reply code */ 33224943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3334577Seric { 3344711Seric num = fmt; 3354711Seric fmt += 4; 3364711Seric } 3374711Seric if (num[3] == '-') 3384711Seric del = '-'; 3394711Seric else 3404711Seric del = ' '; 3414711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3424711Seric eb += 4; 3434063Seric 3449372Seric /* output the file name and line number */ 3459372Seric if (FileName != NULL) 3469372Seric { 3479372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3489372Seric eb += strlen(eb); 3499372Seric } 3509372Seric 3514711Seric /* output the "to" person */ 3524711Seric if (to != NULL && to[0] != '\0') 3534711Seric { 3544711Seric (void) sprintf(eb, "%s... ", to); 3555201Seric while (*eb != '\0') 3565201Seric *eb++ &= 0177; 3574711Seric } 3584711Seric 35959596Seric meb = eb; 36059596Seric 3614711Seric /* output the message */ 36256852Seric (void) vsprintf(eb, fmt, ap); 3635201Seric while (*eb != '\0') 3645201Seric *eb++ &= 0177; 3654711Seric 3664711Seric /* output the error code, if any */ 36716904Seric if (eno != 0) 3684711Seric { 36916904Seric (void) sprintf(eb, ": %s", errstring(eno)); 3704711Seric eb += strlen(eb); 3714577Seric } 37259596Seric 37359734Seric if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL) 37459596Seric CurEnv->e_message = newstr(meb); 375295Seric } 37615136Seric /* 37715136Seric ** ERRSTRING -- return string description of error code 37815136Seric ** 37915136Seric ** Parameters: 38015136Seric ** errno -- the error number to translate 38115136Seric ** 38215136Seric ** Returns: 38315136Seric ** A string description of errno. 38415136Seric ** 38515136Seric ** Side Effects: 38615136Seric ** none. 38715136Seric */ 38815136Seric 38960089Seric const char * 39015136Seric errstring(errno) 39115136Seric int errno; 39215136Seric { 39360089Seric extern const char *const sys_errlist[]; 39415136Seric extern int sys_nerr; 39557232Seric static char buf[MAXLINE]; 39624943Seric # ifdef SMTP 39724943Seric extern char *SmtpPhase; 39856795Seric # endif /* SMTP */ 39915136Seric 40024943Seric # ifdef DAEMON 40152107Seric # ifdef ETIMEDOUT 40224943Seric /* 40324943Seric ** Handle special network error codes. 40424943Seric ** 40524943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 40624943Seric */ 40724943Seric 40824943Seric switch (errno) 40924943Seric { 41024943Seric case ETIMEDOUT: 41124943Seric case ECONNRESET: 41224943Seric (void) strcpy(buf, sys_errlist[errno]); 41324943Seric if (SmtpPhase != NULL) 41424943Seric { 41524943Seric (void) strcat(buf, " during "); 41624943Seric (void) strcat(buf, SmtpPhase); 41724943Seric } 41825050Seric if (CurHostName != NULL) 41924943Seric { 42024943Seric (void) strcat(buf, " with "); 42125050Seric (void) strcat(buf, CurHostName); 42224943Seric } 42324943Seric return (buf); 42424943Seric 42524943Seric case EHOSTDOWN: 42625050Seric if (CurHostName == NULL) 42724943Seric break; 42825050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 42924943Seric return (buf); 43024943Seric 43124943Seric case ECONNREFUSED: 43225050Seric if (CurHostName == NULL) 43324943Seric break; 43425050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 43524943Seric return (buf); 43625526Smiriam 43757736Seric # ifdef NAMED_BIND 43858010Seric case HOST_NOT_FOUND + MAX_ERRNO: 43958010Seric return ("Name server: host not found"); 44058010Seric 44158010Seric case TRY_AGAIN + MAX_ERRNO: 44258010Seric return ("Name server: host name lookup failure"); 44358010Seric 44458010Seric case NO_RECOVERY + MAX_ERRNO: 44558010Seric return ("Name server: non-recoverable error"); 44658010Seric 44758010Seric case NO_DATA + MAX_ERRNO: 44858010Seric return ("Name server: no data known for name"); 44957736Seric # endif 45024943Seric } 45152107Seric # endif 45252107Seric # endif 45324943Seric 45415136Seric if (errno > 0 && errno < sys_nerr) 45515136Seric return (sys_errlist[errno]); 45615136Seric 45715136Seric (void) sprintf(buf, "Error %d", errno); 45815136Seric return (buf); 45915136Seric } 460