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*63848Seric static char sccsid[] = "@(#)err.c 8.4 (Berkeley) 07/17/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 4110147Seric char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 424084Seric 4346928Sbostic static void fmtmsg(); 4446928Sbostic 4558824Seric void 46295Seric /*VARARGS1*/ 4757642Seric #ifdef __STDC__ 4860094Seric syserr(const char *fmt, ...) 4957642Seric #else 5057642Seric syserr(fmt, va_alist) 5160094Seric const char *fmt; 5257642Seric va_dcl 5357642Seric #endif 54295Seric { 5516901Seric register char *p; 5616901Seric int olderrno = errno; 5758690Seric bool panic; 5856852Seric VA_LOCAL_DECL 59295Seric 6058690Seric panic = *fmt == '!'; 6158690Seric if (panic) 6258690Seric fmt++; 6358690Seric 647525Seric /* format and output the error message */ 6516901Seric if (olderrno == 0) 6658151Seric p = "554"; 677957Seric else 6858151Seric p = "451"; 6956852Seric VA_START(fmt); 7056852Seric fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 7156852Seric VA_END; 729389Seric puterrmsg(MsgBuf); 734063Seric 74295Seric /* determine exit status if not already set */ 75295Seric if (ExitStat == EX_OK) 76295Seric { 7716901Seric if (olderrno == 0) 78295Seric ExitStat = EX_SOFTWARE; 79295Seric else 801598Seric ExitStat = EX_OSERR; 81295Seric } 82295Seric 83295Seric # ifdef LOG 847674Seric if (LogLevel > 0) 8558690Seric syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", 8625277Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 8725277Seric &MsgBuf[4]); 8856795Seric # endif /* LOG */ 8958690Seric if (panic) 9059156Seric { 9159156Seric #ifdef XLA 9259156Seric xla_all_end(); 9359156Seric #endif 9458690Seric exit(EX_OSERR); 9559156Seric } 96295Seric errno = 0; 977762Seric if (QuickAbort) 987762Seric longjmp(TopFrame, 2); 99295Seric } 100295Seric /* 101295Seric ** USRERR -- Signal user error. 102295Seric ** 103295Seric ** This is much like syserr except it is for user errors. 104295Seric ** 105295Seric ** Parameters: 106295Seric ** fmt, a, b, c, d -- printf strings 107295Seric ** 108295Seric ** Returns: 1094084Seric ** none 1107762Seric ** Through TopFrame if QuickAbort is set. 111295Seric ** 112295Seric ** Side Effects: 1131514Seric ** increments Errors. 114295Seric */ 115295Seric 116295Seric /*VARARGS1*/ 11758824Seric void 11857642Seric #ifdef __STDC__ 11960094Seric usrerr(const char *fmt, ...) 12057642Seric #else 12157642Seric usrerr(fmt, va_alist) 12260094Seric const char *fmt; 12357642Seric va_dcl 12457642Seric #endif 125295Seric { 12656852Seric VA_LOCAL_DECL 127295Seric extern char SuprErrs; 12816901Seric extern int errno; 129295Seric 130295Seric if (SuprErrs) 1314084Seric return; 132295Seric 13356852Seric VA_START(fmt); 13458524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 13556852Seric VA_END; 1369389Seric puterrmsg(MsgBuf); 1378239Seric 13851951Seric # ifdef LOG 13958020Seric if (LogLevel > 3 && LogUsrErrs) 14051951Seric syslog(LOG_NOTICE, "%s: %s", 14151951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 14251951Seric &MsgBuf[4]); 14356795Seric # endif /* LOG */ 14451951Seric 1457762Seric if (QuickAbort) 1467762Seric longjmp(TopFrame, 1); 1474063Seric } 1484063Seric /* 1494063Seric ** MESSAGE -- print message (not necessarily an error) 1504063Seric ** 1514063Seric ** Parameters: 15259581Seric ** msg -- the message (printf fmt) -- it can begin with 15359581Seric ** an SMTP reply code. If not, 050 is assumed. 1544063Seric ** a, b, c, d, e -- printf arguments 1554063Seric ** 1564063Seric ** Returns: 1574063Seric ** none 1584063Seric ** 1594063Seric ** Side Effects: 1604063Seric ** none. 1614063Seric */ 1624063Seric 1634084Seric /*VARARGS2*/ 16458826Seric void 16557642Seric #ifdef __STDC__ 16660094Seric message(const char *msg, ...) 16757642Seric #else 16858151Seric message(msg, va_alist) 16960094Seric const char *msg; 17057642Seric va_dcl 17157642Seric #endif 1724063Seric { 17356852Seric VA_LOCAL_DECL 17456852Seric 1754711Seric errno = 0; 17656852Seric VA_START(msg); 17758151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 17856852Seric VA_END; 17963753Seric putoutmsg(MsgBuf, FALSE); 1807613Seric } 1817613Seric /* 1828239Seric ** NMESSAGE -- print message (not necessarily an error) 1838239Seric ** 1848239Seric ** Just like "message" except it never puts the to... tag on. 1858239Seric ** 1868239Seric ** Parameters: 1878239Seric ** num -- the default ARPANET error number (in ascii) 1888239Seric ** msg -- the message (printf fmt) -- if it begins 18924943Seric ** with three digits, this number overrides num. 1908239Seric ** a, b, c, d, e -- printf arguments 1918239Seric ** 1928239Seric ** Returns: 1938239Seric ** none 1948239Seric ** 1958239Seric ** Side Effects: 1968239Seric ** none. 1978239Seric */ 1988239Seric 1998239Seric /*VARARGS2*/ 20058826Seric void 20157642Seric #ifdef __STDC__ 20260094Seric nmessage(const char *msg, ...) 20357642Seric #else 20458151Seric nmessage(msg, va_alist) 20560094Seric const char *msg; 20657642Seric va_dcl 20757642Seric #endif 2088239Seric { 20956852Seric VA_LOCAL_DECL 21056852Seric 2118239Seric errno = 0; 21256852Seric VA_START(msg); 21358151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 21456852Seric VA_END; 21563753Seric putoutmsg(MsgBuf, FALSE); 2168239Seric } 2178239Seric /* 21863753Seric ** PUTOUTMSG -- output error message to transcript and channel 2197613Seric ** 2207613Seric ** Parameters: 2217613Seric ** msg -- message to output (in SMTP format). 2229108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2239108Seric ** our output channel. 2247613Seric ** 2257613Seric ** Returns: 2267613Seric ** none. 2277613Seric ** 2287613Seric ** Side Effects: 2297613Seric ** Outputs msg to the transcript. 2307613Seric ** If appropriate, outputs it to the channel. 2317613Seric ** Deletes SMTP reply code number as appropriate. 2327613Seric */ 2334711Seric 23463753Seric putoutmsg(msg, holdmsg) 2357613Seric char *msg; 2369108Seric bool holdmsg; 2377613Seric { 23814900Seric /* output to transcript if serious */ 239*63848Seric if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) 24014900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2414711Seric 2424711Seric /* output to channel if appropriate */ 24360421Seric if (holdmsg || (!Verbose && msg[0] == '0')) 24460421Seric return; 24560421Seric 246*63848Seric /* map warnings to something SMTP can handle */ 247*63848Seric if (msg[0] == '6') 248*63848Seric msg[0] = '5'; 249*63848Seric 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]); 25563753Seric if (TrafficLogFile != NULL) 25663753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 25763753Seric 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, 27263753Seric "%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 /* 27863753Seric ** 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 { 293*63848Seric char msgcode = msg[0]; 294*63848Seric 2959389Seric /* output the message as usual */ 29663753Seric putoutmsg(msg, HoldErrs); 2979389Seric 2989389Seric /* signal the error */ 299*63848Seric if (msgcode == '6') 300*63848Seric { 301*63848Seric /* notify the postmaster */ 302*63848Seric CurEnv->e_flags |= EF_PM_NOTIFY; 303*63848Seric } 304*63848Seric else 305*63848Seric { 306*63848Seric Errors++; 307*63848Seric if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 308*63848Seric CurEnv->e_flags |= EF_FATALERRS; 309*63848Seric } 3104711Seric } 3114711Seric /* 3124711Seric ** FMTMSG -- format a message into buffer. 3134711Seric ** 3144711Seric ** Parameters: 3154711Seric ** eb -- error buffer to get result. 3164711Seric ** to -- the recipient tag for this message. 3174711Seric ** num -- arpanet error number. 31816901Seric ** en -- the error number to display. 3194711Seric ** fmt -- format of string. 3204711Seric ** a, b, c, d, e -- arguments. 3214711Seric ** 3224711Seric ** Returns: 3234711Seric ** none. 3244711Seric ** 3254711Seric ** Side Effects: 3264711Seric ** none. 3274711Seric */ 3284063Seric 32946928Sbostic static void 33056852Seric fmtmsg(eb, to, num, eno, fmt, ap) 3314711Seric register char *eb; 3324711Seric char *to; 3334711Seric char *num; 33416904Seric int eno; 3354711Seric char *fmt; 33656852Seric va_list ap; 3374711Seric { 3384711Seric char del; 33959596Seric char *meb; 3404711Seric 3414711Seric /* output the reply code */ 34224943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3434577Seric { 3444711Seric num = fmt; 3454711Seric fmt += 4; 3464711Seric } 3474711Seric if (num[3] == '-') 3484711Seric del = '-'; 3494711Seric else 3504711Seric del = ' '; 3514711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3524711Seric eb += 4; 3534063Seric 3549372Seric /* output the file name and line number */ 3559372Seric if (FileName != NULL) 3569372Seric { 3579372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3589372Seric eb += strlen(eb); 3599372Seric } 3609372Seric 3614711Seric /* output the "to" person */ 3624711Seric if (to != NULL && to[0] != '\0') 3634711Seric { 3644711Seric (void) sprintf(eb, "%s... ", to); 3655201Seric while (*eb != '\0') 3665201Seric *eb++ &= 0177; 3674711Seric } 3684711Seric 36959596Seric meb = eb; 37059596Seric 3714711Seric /* output the message */ 37256852Seric (void) vsprintf(eb, fmt, ap); 3735201Seric while (*eb != '\0') 3745201Seric *eb++ &= 0177; 3754711Seric 3764711Seric /* output the error code, if any */ 37716904Seric if (eno != 0) 3784711Seric { 37916904Seric (void) sprintf(eb, ": %s", errstring(eno)); 3804711Seric eb += strlen(eb); 3814577Seric } 38259596Seric 38359734Seric if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL) 38459596Seric CurEnv->e_message = newstr(meb); 385295Seric } 38615136Seric /* 38715136Seric ** ERRSTRING -- return string description of error code 38815136Seric ** 38915136Seric ** Parameters: 39015136Seric ** errno -- the error number to translate 39115136Seric ** 39215136Seric ** Returns: 39315136Seric ** A string description of errno. 39415136Seric ** 39515136Seric ** Side Effects: 39615136Seric ** none. 39715136Seric */ 39815136Seric 39960089Seric const char * 40015136Seric errstring(errno) 40115136Seric int errno; 40215136Seric { 40363839Seric static char buf[MAXLINE]; 40463839Seric # ifndef ERRLIST_PREDEFINED 40563839Seric extern char *sys_errlist[]; 40615136Seric extern int sys_nerr; 40763839Seric # endif 40824943Seric # ifdef SMTP 40924943Seric extern char *SmtpPhase; 41056795Seric # endif /* SMTP */ 41115136Seric 41224943Seric # ifdef DAEMON 41352107Seric # ifdef ETIMEDOUT 41424943Seric /* 41524943Seric ** Handle special network error codes. 41624943Seric ** 41724943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 41824943Seric */ 41924943Seric 42024943Seric switch (errno) 42124943Seric { 42224943Seric case ETIMEDOUT: 42324943Seric case ECONNRESET: 42424943Seric (void) strcpy(buf, sys_errlist[errno]); 42524943Seric if (SmtpPhase != NULL) 42624943Seric { 42724943Seric (void) strcat(buf, " during "); 42824943Seric (void) strcat(buf, SmtpPhase); 42924943Seric } 43025050Seric if (CurHostName != NULL) 43124943Seric { 43224943Seric (void) strcat(buf, " with "); 43325050Seric (void) strcat(buf, CurHostName); 43424943Seric } 43524943Seric return (buf); 43624943Seric 43724943Seric case EHOSTDOWN: 43825050Seric if (CurHostName == NULL) 43924943Seric break; 44025050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 44124943Seric return (buf); 44224943Seric 44324943Seric case ECONNREFUSED: 44425050Seric if (CurHostName == NULL) 44524943Seric break; 44625050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 44724943Seric return (buf); 44825526Smiriam 44957736Seric # ifdef NAMED_BIND 45058010Seric case HOST_NOT_FOUND + MAX_ERRNO: 45158010Seric return ("Name server: host not found"); 45258010Seric 45358010Seric case TRY_AGAIN + MAX_ERRNO: 45458010Seric return ("Name server: host name lookup failure"); 45558010Seric 45658010Seric case NO_RECOVERY + MAX_ERRNO: 45758010Seric return ("Name server: non-recoverable error"); 45858010Seric 45958010Seric case NO_DATA + MAX_ERRNO: 46058010Seric return ("Name server: no data known for name"); 46157736Seric # endif 46224943Seric } 46352107Seric # endif 46452107Seric # endif 46524943Seric 46615136Seric if (errno > 0 && errno < sys_nerr) 46715136Seric return (sys_errlist[errno]); 46815136Seric 46915136Seric (void) sprintf(buf, "Error %d", errno); 47015136Seric return (buf); 47115136Seric } 472