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*66864Seric static char sccsid[] = "@(#)err.c 8.27 (Berkeley) 04/18/94"; 1133729Sbostic #endif /* not lint */ 1222705Sdist 133311Seric # include "sendmail.h" 1424943Seric # include <errno.h> 1525526Smiriam # include <netdb.h> 1666006Seric # include <pwd.h> 17295Seric 18295Seric /* 191514Seric ** SYSERR -- Print error message. 20295Seric ** 21295Seric ** Prints an error message via printf to the diagnostic 22295Seric ** output. If LOG is defined, it logs it also. 23295Seric ** 2458690Seric ** If the first character of the syserr message is `!' it will 2558690Seric ** log this as an ALERT message and exit immediately. This can 2658690Seric ** leave queue files in an indeterminate state, so it should not 2758690Seric ** be used lightly. 2858690Seric ** 29295Seric ** Parameters: 30295Seric ** f -- the format string 31295Seric ** a, b, c, d, e -- parameters 32295Seric ** 33295Seric ** Returns: 344084Seric ** none 357762Seric ** Through TopFrame if QuickAbort is set. 36295Seric ** 37295Seric ** Side Effects: 381514Seric ** increments Errors. 391514Seric ** sets ExitStat. 40295Seric */ 41295Seric 4210147Seric char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 434084Seric 4463969Seric static void fmtmsg(); 4546928Sbostic 4666334Seric #if NAMED_BIND && !defined(NO_DATA) 4763969Seric # define NO_DATA NO_ADDRESS 4863969Seric #endif 4963969Seric 5058824Seric void 51295Seric /*VARARGS1*/ 5257642Seric #ifdef __STDC__ 5360094Seric syserr(const char *fmt, ...) 5457642Seric #else 5557642Seric syserr(fmt, va_alist) 5660094Seric const char *fmt; 5757642Seric va_dcl 5857642Seric #endif 59295Seric { 6016901Seric register char *p; 6116901Seric int olderrno = errno; 6258690Seric bool panic; 6366006Seric #ifdef LOG 6466006Seric char *uname; 6566006Seric struct passwd *pw; 6666006Seric char ubuf[80]; 6766006Seric #endif 6856852Seric VA_LOCAL_DECL 69295Seric 7058690Seric panic = *fmt == '!'; 7158690Seric if (panic) 7258690Seric fmt++; 7358690Seric 747525Seric /* format and output the error message */ 7516901Seric if (olderrno == 0) 7658151Seric p = "554"; 777957Seric else 7858151Seric p = "451"; 7956852Seric VA_START(fmt); 8056852Seric fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 8156852Seric VA_END; 829389Seric puterrmsg(MsgBuf); 834063Seric 84295Seric /* determine exit status if not already set */ 85295Seric if (ExitStat == EX_OK) 86295Seric { 8716901Seric if (olderrno == 0) 88295Seric ExitStat = EX_SOFTWARE; 89295Seric else 901598Seric ExitStat = EX_OSERR; 9166323Seric if (tTd(54, 1)) 9266323Seric printf("syserr: ExitStat = %d\n", ExitStat); 93295Seric } 94295Seric 95295Seric # ifdef LOG 9666006Seric pw = getpwuid(getuid()); 9766006Seric if (pw != NULL) 9866006Seric uname = pw->pw_name; 9966006Seric else 10066006Seric { 10166006Seric uname = ubuf; 10266006Seric sprintf(ubuf, "UID%d", getuid()); 10366006Seric } 10466006Seric 1057674Seric if (LogLevel > 0) 10666006Seric syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s", 10725277Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 10866006Seric uname, &MsgBuf[4]); 10956795Seric # endif /* LOG */ 11064725Seric if (olderrno == EMFILE) 11164731Seric { 11264725Seric printopenfds(TRUE); 11364731Seric mci_dump_all(TRUE); 11464731Seric } 11558690Seric if (panic) 11659156Seric { 11759156Seric #ifdef XLA 11859156Seric xla_all_end(); 11959156Seric #endif 12058690Seric exit(EX_OSERR); 12159156Seric } 122295Seric errno = 0; 1237762Seric if (QuickAbort) 1247762Seric longjmp(TopFrame, 2); 125295Seric } 126295Seric /* 127295Seric ** USRERR -- Signal user error. 128295Seric ** 129295Seric ** This is much like syserr except it is for user errors. 130295Seric ** 131295Seric ** Parameters: 132295Seric ** fmt, a, b, c, d -- printf strings 133295Seric ** 134295Seric ** Returns: 1354084Seric ** none 1367762Seric ** Through TopFrame if QuickAbort is set. 137295Seric ** 138295Seric ** Side Effects: 1391514Seric ** increments Errors. 140295Seric */ 141295Seric 142295Seric /*VARARGS1*/ 14358824Seric void 14457642Seric #ifdef __STDC__ 14560094Seric usrerr(const char *fmt, ...) 14657642Seric #else 14757642Seric usrerr(fmt, va_alist) 14860094Seric const char *fmt; 14957642Seric va_dcl 15057642Seric #endif 151295Seric { 15256852Seric VA_LOCAL_DECL 153295Seric 154295Seric if (SuprErrs) 1554084Seric return; 156295Seric 15756852Seric VA_START(fmt); 15858524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 15956852Seric VA_END; 1609389Seric puterrmsg(MsgBuf); 1618239Seric 16251951Seric # ifdef LOG 16358020Seric if (LogLevel > 3 && LogUsrErrs) 16451951Seric syslog(LOG_NOTICE, "%s: %s", 16551951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 16651951Seric &MsgBuf[4]); 16756795Seric # endif /* LOG */ 16851951Seric 1697762Seric if (QuickAbort) 1707762Seric longjmp(TopFrame, 1); 1714063Seric } 1724063Seric /* 1734063Seric ** MESSAGE -- print message (not necessarily an error) 1744063Seric ** 1754063Seric ** Parameters: 17659581Seric ** msg -- the message (printf fmt) -- it can begin with 17759581Seric ** an SMTP reply code. If not, 050 is assumed. 1784063Seric ** a, b, c, d, e -- printf arguments 1794063Seric ** 1804063Seric ** Returns: 1814063Seric ** none 1824063Seric ** 1834063Seric ** Side Effects: 1844063Seric ** none. 1854063Seric */ 1864063Seric 1874084Seric /*VARARGS2*/ 18858826Seric void 18957642Seric #ifdef __STDC__ 19060094Seric message(const char *msg, ...) 19157642Seric #else 19258151Seric message(msg, va_alist) 19360094Seric const char *msg; 19457642Seric va_dcl 19557642Seric #endif 1964063Seric { 19756852Seric VA_LOCAL_DECL 19856852Seric 1994711Seric errno = 0; 20056852Seric VA_START(msg); 20158151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 20256852Seric VA_END; 20363753Seric putoutmsg(MsgBuf, FALSE); 2047613Seric } 2057613Seric /* 2068239Seric ** NMESSAGE -- print message (not necessarily an error) 2078239Seric ** 2088239Seric ** Just like "message" except it never puts the to... tag on. 2098239Seric ** 2108239Seric ** Parameters: 2118239Seric ** num -- the default ARPANET error number (in ascii) 2128239Seric ** msg -- the message (printf fmt) -- if it begins 21324943Seric ** with three digits, this number overrides num. 2148239Seric ** a, b, c, d, e -- printf arguments 2158239Seric ** 2168239Seric ** Returns: 2178239Seric ** none 2188239Seric ** 2198239Seric ** Side Effects: 2208239Seric ** none. 2218239Seric */ 2228239Seric 2238239Seric /*VARARGS2*/ 22458826Seric void 22557642Seric #ifdef __STDC__ 22660094Seric nmessage(const char *msg, ...) 22757642Seric #else 22858151Seric nmessage(msg, va_alist) 22960094Seric const char *msg; 23057642Seric va_dcl 23157642Seric #endif 2328239Seric { 23356852Seric VA_LOCAL_DECL 23456852Seric 2358239Seric errno = 0; 23656852Seric VA_START(msg); 23758151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 23856852Seric VA_END; 23963753Seric putoutmsg(MsgBuf, FALSE); 2408239Seric } 2418239Seric /* 24263753Seric ** PUTOUTMSG -- output error message to transcript and channel 2437613Seric ** 2447613Seric ** Parameters: 2457613Seric ** msg -- message to output (in SMTP format). 2469108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2479108Seric ** our output channel. 2487613Seric ** 2497613Seric ** Returns: 2507613Seric ** none. 2517613Seric ** 2527613Seric ** Side Effects: 2537613Seric ** Outputs msg to the transcript. 2547613Seric ** If appropriate, outputs it to the channel. 2557613Seric ** Deletes SMTP reply code number as appropriate. 2567613Seric */ 2574711Seric 25863753Seric putoutmsg(msg, holdmsg) 2597613Seric char *msg; 2609108Seric bool holdmsg; 2617613Seric { 26264249Seric /* display for debugging */ 26364249Seric if (tTd(54, 8)) 26464249Seric printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); 26564249Seric 26614900Seric /* output to transcript if serious */ 26763848Seric if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) 26814900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2694711Seric 2704711Seric /* output to channel if appropriate */ 27160421Seric if (holdmsg || (!Verbose && msg[0] == '0')) 27260421Seric return; 27360421Seric 27463848Seric /* map warnings to something SMTP can handle */ 27563848Seric if (msg[0] == '6') 27663848Seric msg[0] = '5'; 27763848Seric 27860421Seric (void) fflush(stdout); 27966017Seric 28066017Seric /* if DisConnected, OutChannel now points to the transcript */ 28166017Seric if (!DisConnected && 28266017Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 28360421Seric fprintf(OutChannel, "%s\r\n", msg); 28460421Seric else 28560421Seric fprintf(OutChannel, "%s\n", &msg[4]); 28663753Seric if (TrafficLogFile != NULL) 28763753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 28865580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]); 28960421Seric if (msg[3] == ' ') 29060421Seric (void) fflush(OutChannel); 29166017Seric if (!ferror(OutChannel) || DisConnected) 29260421Seric return; 29360421Seric 29464499Seric /* 29564499Seric ** Error on output -- if reporting lost channel, just ignore it. 29664499Seric ** Also, ignore errors from QUIT response (221 message) -- some 29764499Seric ** rude servers don't read result. 29864499Seric */ 29964499Seric 30064499Seric if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0) 30160421Seric return; 30260421Seric 30360421Seric /* can't call syserr, 'cause we are using MsgBuf */ 30460421Seric HoldErrs = TRUE; 30560283Seric #ifdef LOG 30660421Seric if (LogLevel > 0) 30760421Seric syslog(LOG_CRIT, 308*66864Seric "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 30960421Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 31064123Seric CurHostName == NULL ? "NO-HOST" : CurHostName, 311*66864Seric msg, errstring(errno)); 31260283Seric #endif 3139389Seric } 3149389Seric /* 31563753Seric ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 3169389Seric ** 3179389Seric ** Parameters: 3189389Seric ** msg -- the message to output. 3199389Seric ** 3209389Seric ** Returns: 3219389Seric ** none. 3229389Seric ** 3239389Seric ** Side Effects: 3249389Seric ** Sets the fatal error bit in the envelope as appropriate. 3259389Seric */ 3268239Seric 3279389Seric puterrmsg(msg) 3289389Seric char *msg; 3299389Seric { 33063848Seric char msgcode = msg[0]; 33163848Seric 3329389Seric /* output the message as usual */ 33363753Seric putoutmsg(msg, HoldErrs); 3349389Seric 3359389Seric /* signal the error */ 33664773Seric Errors++; 33763848Seric if (msgcode == '6') 33863848Seric { 33963848Seric /* notify the postmaster */ 34063848Seric CurEnv->e_flags |= EF_PM_NOTIFY; 34163848Seric } 34264773Seric else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 34364773Seric { 34464773Seric /* mark long-term fatal errors */ 34564773Seric CurEnv->e_flags |= EF_FATALERRS; 34664773Seric } 3474711Seric } 3484711Seric /* 3494711Seric ** FMTMSG -- format a message into buffer. 3504711Seric ** 3514711Seric ** Parameters: 3524711Seric ** eb -- error buffer to get result. 3534711Seric ** to -- the recipient tag for this message. 3544711Seric ** num -- arpanet error number. 35516901Seric ** en -- the error number to display. 3564711Seric ** fmt -- format of string. 3574711Seric ** a, b, c, d, e -- arguments. 3584711Seric ** 3594711Seric ** Returns: 3604711Seric ** none. 3614711Seric ** 3624711Seric ** Side Effects: 3634711Seric ** none. 3644711Seric */ 3654063Seric 36646928Sbostic static void 36756852Seric fmtmsg(eb, to, num, eno, fmt, ap) 3684711Seric register char *eb; 3694711Seric char *to; 3704711Seric char *num; 37116904Seric int eno; 3724711Seric char *fmt; 37356852Seric va_list ap; 3744711Seric { 3754711Seric char del; 37659596Seric char *meb; 3774711Seric 3784711Seric /* output the reply code */ 37924943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3804577Seric { 3814711Seric num = fmt; 3824711Seric fmt += 4; 3834711Seric } 3844711Seric if (num[3] == '-') 3854711Seric del = '-'; 3864711Seric else 3874711Seric del = ' '; 3884711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3894711Seric eb += 4; 3904063Seric 3919372Seric /* output the file name and line number */ 3929372Seric if (FileName != NULL) 3939372Seric { 3949372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3959372Seric eb += strlen(eb); 3969372Seric } 3979372Seric 3984711Seric /* output the "to" person */ 3994711Seric if (to != NULL && to[0] != '\0') 4004711Seric { 40166297Seric (void) sprintf(eb, "%s... ", shortenstring(to, 203)); 4025201Seric while (*eb != '\0') 4035201Seric *eb++ &= 0177; 4044711Seric } 4054711Seric 40659596Seric meb = eb; 40759596Seric 4084711Seric /* output the message */ 40956852Seric (void) vsprintf(eb, fmt, ap); 4105201Seric while (*eb != '\0') 4115201Seric *eb++ &= 0177; 4124711Seric 4134711Seric /* output the error code, if any */ 41416904Seric if (eno != 0) 4154711Seric { 41616904Seric (void) sprintf(eb, ": %s", errstring(eno)); 4174711Seric eb += strlen(eb); 4184577Seric } 41959596Seric 42064695Seric if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) 42164695Seric { 42264695Seric if (CurEnv->e_message != NULL) 42364695Seric free(CurEnv->e_message); 42459596Seric CurEnv->e_message = newstr(meb); 42564695Seric } 426295Seric } 42715136Seric /* 42815136Seric ** ERRSTRING -- return string description of error code 42915136Seric ** 43015136Seric ** Parameters: 43165751Seric ** errnum -- the error number to translate 43215136Seric ** 43315136Seric ** Returns: 43465751Seric ** A string description of errnum. 43515136Seric ** 43615136Seric ** Side Effects: 43715136Seric ** none. 43815136Seric */ 43915136Seric 44060089Seric const char * 44165751Seric errstring(errnum) 44265751Seric int errnum; 44315136Seric { 44465168Seric char *dnsmsg; 44563839Seric static char buf[MAXLINE]; 44663839Seric # ifndef ERRLIST_PREDEFINED 44763839Seric extern char *sys_errlist[]; 44815136Seric extern int sys_nerr; 44963839Seric # endif 45024943Seric # ifdef SMTP 45124943Seric extern char *SmtpPhase; 45256795Seric # endif /* SMTP */ 45315136Seric 45424943Seric /* 45524943Seric ** Handle special network error codes. 45624943Seric ** 45724943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 45824943Seric */ 45924943Seric 46065168Seric dnsmsg = NULL; 46165751Seric switch (errnum) 46224943Seric { 46365067Seric # if defined(DAEMON) && defined(ETIMEDOUT) 46424943Seric case ETIMEDOUT: 46524943Seric case ECONNRESET: 46665751Seric (void) strcpy(buf, sys_errlist[errnum]); 46724943Seric if (SmtpPhase != NULL) 46824943Seric { 46924943Seric (void) strcat(buf, " during "); 47024943Seric (void) strcat(buf, SmtpPhase); 47124943Seric } 47225050Seric if (CurHostName != NULL) 47324943Seric { 47424943Seric (void) strcat(buf, " with "); 47525050Seric (void) strcat(buf, CurHostName); 47624943Seric } 47724943Seric return (buf); 47824943Seric 47924943Seric case EHOSTDOWN: 48025050Seric if (CurHostName == NULL) 48124943Seric break; 48225050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 48324943Seric return (buf); 48424943Seric 48524943Seric case ECONNREFUSED: 48625050Seric if (CurHostName == NULL) 48724943Seric break; 48825050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 48924943Seric return (buf); 49065067Seric # endif 49125526Smiriam 49263993Seric case EOPENTIMEOUT: 49363993Seric return "Timeout on file open"; 49463993Seric 49566334Seric # if NAMED_BIND 49663993Seric case HOST_NOT_FOUND + E_DNSBASE: 49765168Seric dnsmsg = "host not found"; 49865168Seric break; 49958010Seric 50063993Seric case TRY_AGAIN + E_DNSBASE: 50165168Seric dnsmsg = "host name lookup failure"; 50265168Seric break; 50358010Seric 50463993Seric case NO_RECOVERY + E_DNSBASE: 50565168Seric dnsmsg = "non-recoverable error"; 50665168Seric break; 50758010Seric 50863993Seric case NO_DATA + E_DNSBASE: 50965168Seric dnsmsg = "no data known"; 51065168Seric break; 51157736Seric # endif 51265067Seric 51365067Seric case EPERM: 51465067Seric /* SunOS gives "Not owner" -- this is the POSIX message */ 51565067Seric return "Operation not permitted"; 51624943Seric } 51724943Seric 51865168Seric if (dnsmsg != NULL) 51965168Seric { 52065168Seric (void) strcpy(buf, "Name server: "); 52165168Seric if (CurHostName != NULL) 52265168Seric { 52365168Seric (void) strcat(buf, CurHostName); 52465168Seric (void) strcat(buf, ": "); 52565168Seric } 52665168Seric (void) strcat(buf, dnsmsg); 52765168Seric return buf; 52865168Seric } 52965168Seric 53065751Seric if (errnum > 0 && errnum < sys_nerr) 53165751Seric return (sys_errlist[errnum]); 53215136Seric 53365751Seric (void) sprintf(buf, "Error %d", errnum); 53415136Seric return (buf); 53515136Seric } 536