122705Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333729Sbostic * Copyright (c) 1988 Regents of the University of California. 433729Sbostic * All rights reserved. 533729Sbostic * 642826Sbostic * %sccs.include.redist.c% 733729Sbostic */ 822705Sdist 922705Sdist #ifndef lint 10*58826Seric static char sccsid[] = "@(#)err.c 6.11 (Berkeley) 03/26/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__ 5257642Seric syserr(char *fmt, ...) 5357642Seric #else 5457642Seric syserr(fmt, va_alist) 55295Seric 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) 9458690Seric exit(EX_OSERR); 95295Seric errno = 0; 967762Seric if (QuickAbort) 977762Seric longjmp(TopFrame, 2); 98295Seric } 99295Seric /* 100295Seric ** USRERR -- Signal user error. 101295Seric ** 102295Seric ** This is much like syserr except it is for user errors. 103295Seric ** 104295Seric ** Parameters: 105295Seric ** fmt, a, b, c, d -- printf strings 106295Seric ** 107295Seric ** Returns: 1084084Seric ** none 1097762Seric ** Through TopFrame if QuickAbort is set. 110295Seric ** 111295Seric ** Side Effects: 1121514Seric ** increments Errors. 113295Seric */ 114295Seric 115295Seric /*VARARGS1*/ 11658824Seric void 11757642Seric #ifdef __STDC__ 11857642Seric usrerr(char *fmt, ...) 11957642Seric #else 12057642Seric usrerr(fmt, va_alist) 121295Seric char *fmt; 12257642Seric va_dcl 12357642Seric #endif 124295Seric { 12556852Seric VA_LOCAL_DECL 126295Seric extern char SuprErrs; 12716901Seric extern int errno; 128295Seric 129295Seric if (SuprErrs) 1304084Seric return; 131295Seric 13256852Seric VA_START(fmt); 13358524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 13456852Seric VA_END; 1359389Seric puterrmsg(MsgBuf); 1368239Seric 13751951Seric # ifdef LOG 13858020Seric if (LogLevel > 3 && LogUsrErrs) 13951951Seric syslog(LOG_NOTICE, "%s: %s", 14051951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 14151951Seric &MsgBuf[4]); 14256795Seric # endif /* LOG */ 14351951Seric 1447762Seric if (QuickAbort) 1457762Seric longjmp(TopFrame, 1); 1464063Seric } 1474063Seric /* 1484063Seric ** MESSAGE -- print message (not necessarily an error) 1494063Seric ** 1504063Seric ** Parameters: 1514063Seric ** num -- the default ARPANET error number (in ascii) 1524063Seric ** msg -- the message (printf fmt) -- if it begins 1534063Seric ** with a digit, this number overrides num. 1544063Seric ** a, b, c, d, e -- printf arguments 1554063Seric ** 1564063Seric ** Returns: 1574063Seric ** none 1584063Seric ** 1594063Seric ** Side Effects: 1604063Seric ** none. 1614063Seric */ 1624063Seric 1634084Seric /*VARARGS2*/ 164*58826Seric void 16557642Seric #ifdef __STDC__ 16658151Seric message(char *msg, ...) 16757642Seric #else 16858151Seric message(msg, va_alist) 16956852Seric 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; 1799108Seric putmsg(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*/ 200*58826Seric void 20157642Seric #ifdef __STDC__ 20258151Seric nmessage(char *msg, ...) 20357642Seric #else 20458151Seric nmessage(msg, va_alist) 20556852Seric 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; 2159108Seric putmsg(MsgBuf, FALSE); 2168239Seric } 2178239Seric /* 2187613Seric ** PUTMSG -- 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 2349108Seric putmsg(msg, holdmsg) 2357613Seric char *msg; 2369108Seric bool holdmsg; 2377613Seric { 23814900Seric /* output to transcript if serious */ 23914900Seric if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5')) 24014900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2414711Seric 2424711Seric /* output to channel if appropriate */ 2439108Seric if (!holdmsg && (Verbose || msg[0] != '0')) 2444063Seric { 2457275Seric (void) fflush(stdout); 24652220Seric if (OpMode == MD_SMTP) 2477613Seric fprintf(OutChannel, "%s\r\n", msg); 2484711Seric else 2497613Seric fprintf(OutChannel, "%s\n", &msg[4]); 2504711Seric (void) fflush(OutChannel); 2514063Seric } 2529389Seric } 2539389Seric /* 2549389Seric ** PUTERRMSG -- like putmsg, but does special processing for error messages 2559389Seric ** 2569389Seric ** Parameters: 2579389Seric ** msg -- the message to output. 2589389Seric ** 2599389Seric ** Returns: 2609389Seric ** none. 2619389Seric ** 2629389Seric ** Side Effects: 2639389Seric ** Sets the fatal error bit in the envelope as appropriate. 2649389Seric */ 2658239Seric 2669389Seric puterrmsg(msg) 2679389Seric char *msg; 2689389Seric { 2699389Seric /* output the message as usual */ 2709389Seric putmsg(msg, HoldErrs); 2719389Seric 2729389Seric /* signal the error */ 2739389Seric Errors++; 2749389Seric if (msg[0] == '5') 2759336Seric CurEnv->e_flags |= EF_FATALERRS; 2764711Seric } 2774711Seric /* 2784711Seric ** FMTMSG -- format a message into buffer. 2794711Seric ** 2804711Seric ** Parameters: 2814711Seric ** eb -- error buffer to get result. 2824711Seric ** to -- the recipient tag for this message. 2834711Seric ** num -- arpanet error number. 28416901Seric ** en -- the error number to display. 2854711Seric ** fmt -- format of string. 2864711Seric ** a, b, c, d, e -- arguments. 2874711Seric ** 2884711Seric ** Returns: 2894711Seric ** none. 2904711Seric ** 2914711Seric ** Side Effects: 2924711Seric ** none. 2934711Seric */ 2944063Seric 29546928Sbostic static void 29656852Seric fmtmsg(eb, to, num, eno, fmt, ap) 2974711Seric register char *eb; 2984711Seric char *to; 2994711Seric char *num; 30016904Seric int eno; 3014711Seric char *fmt; 30256852Seric va_list ap; 3034711Seric { 3044711Seric char del; 3054711Seric 3064711Seric /* output the reply code */ 30724943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3084577Seric { 3094711Seric num = fmt; 3104711Seric fmt += 4; 3114711Seric } 3124711Seric if (num[3] == '-') 3134711Seric del = '-'; 3144711Seric else 3154711Seric del = ' '; 3164711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3174711Seric eb += 4; 3184063Seric 3199372Seric /* output the file name and line number */ 3209372Seric if (FileName != NULL) 3219372Seric { 3229372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3239372Seric eb += strlen(eb); 3249372Seric } 3259372Seric 3264711Seric /* output the "to" person */ 3274711Seric if (to != NULL && to[0] != '\0') 3284711Seric { 3294711Seric (void) sprintf(eb, "%s... ", to); 3305201Seric while (*eb != '\0') 3315201Seric *eb++ &= 0177; 3324711Seric } 3334711Seric 3344711Seric /* output the message */ 33556852Seric (void) vsprintf(eb, fmt, ap); 3365201Seric while (*eb != '\0') 3375201Seric *eb++ &= 0177; 3384711Seric 3394711Seric /* output the error code, if any */ 34016904Seric if (eno != 0) 3414711Seric { 34215136Seric extern char *errstring(); 34315136Seric 34416904Seric (void) sprintf(eb, ": %s", errstring(eno)); 3454711Seric eb += strlen(eb); 3464577Seric } 347295Seric } 34815136Seric /* 34915136Seric ** ERRSTRING -- return string description of error code 35015136Seric ** 35115136Seric ** Parameters: 35215136Seric ** errno -- the error number to translate 35315136Seric ** 35415136Seric ** Returns: 35515136Seric ** A string description of errno. 35615136Seric ** 35715136Seric ** Side Effects: 35815136Seric ** none. 35915136Seric */ 36015136Seric 36115136Seric char * 36215136Seric errstring(errno) 36315136Seric int errno; 36415136Seric { 36515136Seric extern char *sys_errlist[]; 36615136Seric extern int sys_nerr; 36757232Seric static char buf[MAXLINE]; 36824943Seric # ifdef SMTP 36924943Seric extern char *SmtpPhase; 37056795Seric # endif /* SMTP */ 37115136Seric 37224943Seric # ifdef DAEMON 37352107Seric # ifdef ETIMEDOUT 37424943Seric /* 37524943Seric ** Handle special network error codes. 37624943Seric ** 37724943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 37824943Seric */ 37924943Seric 38024943Seric switch (errno) 38124943Seric { 38224943Seric case ETIMEDOUT: 38324943Seric case ECONNRESET: 38424943Seric (void) strcpy(buf, sys_errlist[errno]); 38524943Seric if (SmtpPhase != NULL) 38624943Seric { 38724943Seric (void) strcat(buf, " during "); 38824943Seric (void) strcat(buf, SmtpPhase); 38924943Seric } 39025050Seric if (CurHostName != NULL) 39124943Seric { 39224943Seric (void) strcat(buf, " with "); 39325050Seric (void) strcat(buf, CurHostName); 39424943Seric } 39524943Seric return (buf); 39624943Seric 39724943Seric case EHOSTDOWN: 39825050Seric if (CurHostName == NULL) 39924943Seric break; 40025050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 40124943Seric return (buf); 40224943Seric 40324943Seric case ECONNREFUSED: 40425050Seric if (CurHostName == NULL) 40524943Seric break; 40625050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 40724943Seric return (buf); 40825526Smiriam 40957736Seric # ifdef NAMED_BIND 41058010Seric case HOST_NOT_FOUND + MAX_ERRNO: 41158010Seric return ("Name server: host not found"); 41258010Seric 41358010Seric case TRY_AGAIN + MAX_ERRNO: 41458010Seric return ("Name server: host name lookup failure"); 41558010Seric 41658010Seric case NO_RECOVERY + MAX_ERRNO: 41758010Seric return ("Name server: non-recoverable error"); 41858010Seric 41958010Seric case NO_DATA + MAX_ERRNO: 42058010Seric return ("Name server: no data known for name"); 42157736Seric # endif 42224943Seric } 42352107Seric # endif 42452107Seric # endif 42524943Seric 42615136Seric if (errno > 0 && errno < sys_nerr) 42715136Seric return (sys_errlist[errno]); 42815136Seric 42915136Seric (void) sprintf(buf, "Error %d", errno); 43015136Seric return (buf); 43115136Seric } 432