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*66006Seric static char sccsid[] = "@(#)err.c 8.22 (Berkeley) 02/06/94"; 1133729Sbostic #endif /* not lint */ 1222705Sdist 133311Seric # include "sendmail.h" 1424943Seric # include <errno.h> 1525526Smiriam # include <netdb.h> 16*66006Seric # 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 4663969Seric #if defined(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; 63*66006Seric #ifdef LOG 64*66006Seric char *uname; 65*66006Seric struct passwd *pw; 66*66006Seric char ubuf[80]; 67*66006Seric #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; 91295Seric } 92295Seric 93295Seric # ifdef LOG 94*66006Seric pw = getpwuid(getuid()); 95*66006Seric if (pw != NULL) 96*66006Seric uname = pw->pw_name; 97*66006Seric else 98*66006Seric { 99*66006Seric uname = ubuf; 100*66006Seric sprintf(ubuf, "UID%d", getuid()); 101*66006Seric } 102*66006Seric 1037674Seric if (LogLevel > 0) 104*66006Seric syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR(%s): %s", 10525277Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 106*66006Seric uname, &MsgBuf[4]); 10756795Seric # endif /* LOG */ 10864725Seric if (olderrno == EMFILE) 10964731Seric { 11064725Seric printopenfds(TRUE); 11164731Seric mci_dump_all(TRUE); 11264731Seric } 11358690Seric if (panic) 11459156Seric { 11559156Seric #ifdef XLA 11659156Seric xla_all_end(); 11759156Seric #endif 11858690Seric exit(EX_OSERR); 11959156Seric } 120295Seric errno = 0; 1217762Seric if (QuickAbort) 1227762Seric longjmp(TopFrame, 2); 123295Seric } 124295Seric /* 125295Seric ** USRERR -- Signal user error. 126295Seric ** 127295Seric ** This is much like syserr except it is for user errors. 128295Seric ** 129295Seric ** Parameters: 130295Seric ** fmt, a, b, c, d -- printf strings 131295Seric ** 132295Seric ** Returns: 1334084Seric ** none 1347762Seric ** Through TopFrame if QuickAbort is set. 135295Seric ** 136295Seric ** Side Effects: 1371514Seric ** increments Errors. 138295Seric */ 139295Seric 140295Seric /*VARARGS1*/ 14158824Seric void 14257642Seric #ifdef __STDC__ 14360094Seric usrerr(const char *fmt, ...) 14457642Seric #else 14557642Seric usrerr(fmt, va_alist) 14660094Seric const char *fmt; 14757642Seric va_dcl 14857642Seric #endif 149295Seric { 15056852Seric VA_LOCAL_DECL 151295Seric 152295Seric if (SuprErrs) 1534084Seric return; 154295Seric 15556852Seric VA_START(fmt); 15658524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 15756852Seric VA_END; 1589389Seric puterrmsg(MsgBuf); 1598239Seric 16051951Seric # ifdef LOG 16158020Seric if (LogLevel > 3 && LogUsrErrs) 16251951Seric syslog(LOG_NOTICE, "%s: %s", 16351951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 16451951Seric &MsgBuf[4]); 16556795Seric # endif /* LOG */ 16651951Seric 1677762Seric if (QuickAbort) 1687762Seric longjmp(TopFrame, 1); 1694063Seric } 1704063Seric /* 1714063Seric ** MESSAGE -- print message (not necessarily an error) 1724063Seric ** 1734063Seric ** Parameters: 17459581Seric ** msg -- the message (printf fmt) -- it can begin with 17559581Seric ** an SMTP reply code. If not, 050 is assumed. 1764063Seric ** a, b, c, d, e -- printf arguments 1774063Seric ** 1784063Seric ** Returns: 1794063Seric ** none 1804063Seric ** 1814063Seric ** Side Effects: 1824063Seric ** none. 1834063Seric */ 1844063Seric 1854084Seric /*VARARGS2*/ 18658826Seric void 18757642Seric #ifdef __STDC__ 18860094Seric message(const char *msg, ...) 18957642Seric #else 19058151Seric message(msg, va_alist) 19160094Seric const char *msg; 19257642Seric va_dcl 19357642Seric #endif 1944063Seric { 19556852Seric VA_LOCAL_DECL 19656852Seric 1974711Seric errno = 0; 19856852Seric VA_START(msg); 19958151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 20056852Seric VA_END; 20163753Seric putoutmsg(MsgBuf, FALSE); 2027613Seric } 2037613Seric /* 2048239Seric ** NMESSAGE -- print message (not necessarily an error) 2058239Seric ** 2068239Seric ** Just like "message" except it never puts the to... tag on. 2078239Seric ** 2088239Seric ** Parameters: 2098239Seric ** num -- the default ARPANET error number (in ascii) 2108239Seric ** msg -- the message (printf fmt) -- if it begins 21124943Seric ** with three digits, this number overrides num. 2128239Seric ** a, b, c, d, e -- printf arguments 2138239Seric ** 2148239Seric ** Returns: 2158239Seric ** none 2168239Seric ** 2178239Seric ** Side Effects: 2188239Seric ** none. 2198239Seric */ 2208239Seric 2218239Seric /*VARARGS2*/ 22258826Seric void 22357642Seric #ifdef __STDC__ 22460094Seric nmessage(const char *msg, ...) 22557642Seric #else 22658151Seric nmessage(msg, va_alist) 22760094Seric const char *msg; 22857642Seric va_dcl 22957642Seric #endif 2308239Seric { 23156852Seric VA_LOCAL_DECL 23256852Seric 2338239Seric errno = 0; 23456852Seric VA_START(msg); 23558151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 23656852Seric VA_END; 23763753Seric putoutmsg(MsgBuf, FALSE); 2388239Seric } 2398239Seric /* 24063753Seric ** PUTOUTMSG -- output error message to transcript and channel 2417613Seric ** 2427613Seric ** Parameters: 2437613Seric ** msg -- message to output (in SMTP format). 2449108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2459108Seric ** our output channel. 2467613Seric ** 2477613Seric ** Returns: 2487613Seric ** none. 2497613Seric ** 2507613Seric ** Side Effects: 2517613Seric ** Outputs msg to the transcript. 2527613Seric ** If appropriate, outputs it to the channel. 2537613Seric ** Deletes SMTP reply code number as appropriate. 2547613Seric */ 2554711Seric 25663753Seric putoutmsg(msg, holdmsg) 2577613Seric char *msg; 2589108Seric bool holdmsg; 2597613Seric { 26064249Seric /* display for debugging */ 26164249Seric if (tTd(54, 8)) 26264249Seric printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); 26364249Seric 26414900Seric /* output to transcript if serious */ 26563848Seric if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) 26614900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2674711Seric 2684711Seric /* output to channel if appropriate */ 26960421Seric if (holdmsg || (!Verbose && msg[0] == '0')) 27060421Seric return; 27160421Seric 27263848Seric /* map warnings to something SMTP can handle */ 27363848Seric if (msg[0] == '6') 27463848Seric msg[0] = '5'; 27563848Seric 27660421Seric (void) fflush(stdout); 27765983Seric if (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP) 27860421Seric fprintf(OutChannel, "%s\r\n", msg); 27960421Seric else 28060421Seric fprintf(OutChannel, "%s\n", &msg[4]); 28163753Seric if (TrafficLogFile != NULL) 28263753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 28365580Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]); 28460421Seric if (msg[3] == ' ') 28560421Seric (void) fflush(OutChannel); 28660421Seric if (!ferror(OutChannel)) 28760421Seric return; 28860421Seric 28964499Seric /* 29064499Seric ** Error on output -- if reporting lost channel, just ignore it. 29164499Seric ** Also, ignore errors from QUIT response (221 message) -- some 29264499Seric ** rude servers don't read result. 29364499Seric */ 29464499Seric 29564499Seric if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0) 29660421Seric return; 29760421Seric 29860421Seric /* can't call syserr, 'cause we are using MsgBuf */ 29960421Seric HoldErrs = TRUE; 30060283Seric #ifdef LOG 30160421Seric if (LogLevel > 0) 30260421Seric syslog(LOG_CRIT, 30364499Seric "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %m", 30460421Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 30564123Seric CurHostName == NULL ? "NO-HOST" : CurHostName, 30664123Seric msg); 30760283Seric #endif 3089389Seric } 3099389Seric /* 31063753Seric ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 3119389Seric ** 3129389Seric ** Parameters: 3139389Seric ** msg -- the message to output. 3149389Seric ** 3159389Seric ** Returns: 3169389Seric ** none. 3179389Seric ** 3189389Seric ** Side Effects: 3199389Seric ** Sets the fatal error bit in the envelope as appropriate. 3209389Seric */ 3218239Seric 3229389Seric puterrmsg(msg) 3239389Seric char *msg; 3249389Seric { 32563848Seric char msgcode = msg[0]; 32663848Seric 3279389Seric /* output the message as usual */ 32863753Seric putoutmsg(msg, HoldErrs); 3299389Seric 3309389Seric /* signal the error */ 33164773Seric Errors++; 33263848Seric if (msgcode == '6') 33363848Seric { 33463848Seric /* notify the postmaster */ 33563848Seric CurEnv->e_flags |= EF_PM_NOTIFY; 33663848Seric } 33764773Seric else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 33864773Seric { 33964773Seric /* mark long-term fatal errors */ 34064773Seric CurEnv->e_flags |= EF_FATALERRS; 34164773Seric } 3424711Seric } 3434711Seric /* 3444711Seric ** FMTMSG -- format a message into buffer. 3454711Seric ** 3464711Seric ** Parameters: 3474711Seric ** eb -- error buffer to get result. 3484711Seric ** to -- the recipient tag for this message. 3494711Seric ** num -- arpanet error number. 35016901Seric ** en -- the error number to display. 3514711Seric ** fmt -- format of string. 3524711Seric ** a, b, c, d, e -- arguments. 3534711Seric ** 3544711Seric ** Returns: 3554711Seric ** none. 3564711Seric ** 3574711Seric ** Side Effects: 3584711Seric ** none. 3594711Seric */ 3604063Seric 36146928Sbostic static void 36256852Seric fmtmsg(eb, to, num, eno, fmt, ap) 3634711Seric register char *eb; 3644711Seric char *to; 3654711Seric char *num; 36616904Seric int eno; 3674711Seric char *fmt; 36856852Seric va_list ap; 3694711Seric { 3704711Seric char del; 37159596Seric char *meb; 3724711Seric 3734711Seric /* output the reply code */ 37424943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3754577Seric { 3764711Seric num = fmt; 3774711Seric fmt += 4; 3784711Seric } 3794711Seric if (num[3] == '-') 3804711Seric del = '-'; 3814711Seric else 3824711Seric del = ' '; 3834711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3844711Seric eb += 4; 3854063Seric 3869372Seric /* output the file name and line number */ 3879372Seric if (FileName != NULL) 3889372Seric { 3899372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3909372Seric eb += strlen(eb); 3919372Seric } 3929372Seric 3934711Seric /* output the "to" person */ 3944711Seric if (to != NULL && to[0] != '\0') 3954711Seric { 3964711Seric (void) sprintf(eb, "%s... ", to); 3975201Seric while (*eb != '\0') 3985201Seric *eb++ &= 0177; 3994711Seric } 4004711Seric 40159596Seric meb = eb; 40259596Seric 4034711Seric /* output the message */ 40456852Seric (void) vsprintf(eb, fmt, ap); 4055201Seric while (*eb != '\0') 4065201Seric *eb++ &= 0177; 4074711Seric 4084711Seric /* output the error code, if any */ 40916904Seric if (eno != 0) 4104711Seric { 41116904Seric (void) sprintf(eb, ": %s", errstring(eno)); 4124711Seric eb += strlen(eb); 4134577Seric } 41459596Seric 41564695Seric if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) 41664695Seric { 41764695Seric if (CurEnv->e_message != NULL) 41864695Seric free(CurEnv->e_message); 41959596Seric CurEnv->e_message = newstr(meb); 42064695Seric } 421295Seric } 42215136Seric /* 42315136Seric ** ERRSTRING -- return string description of error code 42415136Seric ** 42515136Seric ** Parameters: 42665751Seric ** errnum -- the error number to translate 42715136Seric ** 42815136Seric ** Returns: 42965751Seric ** A string description of errnum. 43015136Seric ** 43115136Seric ** Side Effects: 43215136Seric ** none. 43315136Seric */ 43415136Seric 43560089Seric const char * 43665751Seric errstring(errnum) 43765751Seric int errnum; 43815136Seric { 43965168Seric char *dnsmsg; 44063839Seric static char buf[MAXLINE]; 44163839Seric # ifndef ERRLIST_PREDEFINED 44263839Seric extern char *sys_errlist[]; 44315136Seric extern int sys_nerr; 44463839Seric # endif 44524943Seric # ifdef SMTP 44624943Seric extern char *SmtpPhase; 44756795Seric # endif /* SMTP */ 44815136Seric 44924943Seric /* 45024943Seric ** Handle special network error codes. 45124943Seric ** 45224943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 45324943Seric */ 45424943Seric 45565168Seric dnsmsg = NULL; 45665751Seric switch (errnum) 45724943Seric { 45865067Seric # if defined(DAEMON) && defined(ETIMEDOUT) 45924943Seric case ETIMEDOUT: 46024943Seric case ECONNRESET: 46165751Seric (void) strcpy(buf, sys_errlist[errnum]); 46224943Seric if (SmtpPhase != NULL) 46324943Seric { 46424943Seric (void) strcat(buf, " during "); 46524943Seric (void) strcat(buf, SmtpPhase); 46624943Seric } 46725050Seric if (CurHostName != NULL) 46824943Seric { 46924943Seric (void) strcat(buf, " with "); 47025050Seric (void) strcat(buf, CurHostName); 47124943Seric } 47224943Seric return (buf); 47324943Seric 47424943Seric case EHOSTDOWN: 47525050Seric if (CurHostName == NULL) 47624943Seric break; 47725050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 47824943Seric return (buf); 47924943Seric 48024943Seric case ECONNREFUSED: 48125050Seric if (CurHostName == NULL) 48224943Seric break; 48325050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 48424943Seric return (buf); 48565067Seric # endif 48625526Smiriam 48763993Seric case EOPENTIMEOUT: 48863993Seric return "Timeout on file open"; 48963993Seric 49057736Seric # ifdef NAMED_BIND 49163993Seric case HOST_NOT_FOUND + E_DNSBASE: 49265168Seric dnsmsg = "host not found"; 49365168Seric break; 49458010Seric 49563993Seric case TRY_AGAIN + E_DNSBASE: 49665168Seric dnsmsg = "host name lookup failure"; 49765168Seric break; 49858010Seric 49963993Seric case NO_RECOVERY + E_DNSBASE: 50065168Seric dnsmsg = "non-recoverable error"; 50165168Seric break; 50258010Seric 50363993Seric case NO_DATA + E_DNSBASE: 50465168Seric dnsmsg = "no data known"; 50565168Seric break; 50657736Seric # endif 50765067Seric 50865067Seric case EPERM: 50965067Seric /* SunOS gives "Not owner" -- this is the POSIX message */ 51065067Seric return "Operation not permitted"; 51124943Seric } 51224943Seric 51365168Seric if (dnsmsg != NULL) 51465168Seric { 51565168Seric (void) strcpy(buf, "Name server: "); 51665168Seric if (CurHostName != NULL) 51765168Seric { 51865168Seric (void) strcat(buf, CurHostName); 51965168Seric (void) strcat(buf, ": "); 52065168Seric } 52165168Seric (void) strcat(buf, dnsmsg); 52265168Seric return buf; 52365168Seric } 52465168Seric 52565751Seric if (errnum > 0 && errnum < sys_nerr) 52665751Seric return (sys_errlist[errnum]); 52715136Seric 52865751Seric (void) sprintf(buf, "Error %d", errnum); 52915136Seric return (buf); 53015136Seric } 531