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*58690Seric static char sccsid[] = "@(#)err.c 6.8 (Berkeley) 03/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 ** 23*58690Seric ** If the first character of the syserr message is `!' it will 24*58690Seric ** log this as an ALERT message and exit immediately. This can 25*58690Seric ** leave queue files in an indeterminate state, so it should not 26*58690Seric ** be used lightly. 27*58690Seric ** 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 49295Seric /*VARARGS1*/ 5057642Seric #ifdef __STDC__ 5157642Seric syserr(char *fmt, ...) 5257642Seric #else 5357642Seric syserr(fmt, va_alist) 54295Seric char *fmt; 5557642Seric va_dcl 5657642Seric #endif 57295Seric { 5816901Seric register char *p; 5916901Seric int olderrno = errno; 60*58690Seric bool panic; 6156852Seric VA_LOCAL_DECL 62295Seric 63*58690Seric panic = *fmt == '!'; 64*58690Seric if (panic) 65*58690Seric fmt++; 66*58690Seric 677525Seric /* format and output the error message */ 6816901Seric if (olderrno == 0) 6958151Seric p = "554"; 707957Seric else 7158151Seric p = "451"; 7256852Seric VA_START(fmt); 7356852Seric fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 7456852Seric VA_END; 759389Seric puterrmsg(MsgBuf); 764063Seric 77295Seric /* determine exit status if not already set */ 78295Seric if (ExitStat == EX_OK) 79295Seric { 8016901Seric if (olderrno == 0) 81295Seric ExitStat = EX_SOFTWARE; 82295Seric else 831598Seric ExitStat = EX_OSERR; 84295Seric } 85295Seric 86295Seric # ifdef LOG 877674Seric if (LogLevel > 0) 88*58690Seric syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", 8925277Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 9025277Seric &MsgBuf[4]); 9156795Seric # endif /* LOG */ 92*58690Seric if (panic) 93*58690Seric exit(EX_OSERR); 94295Seric errno = 0; 957762Seric if (QuickAbort) 967762Seric longjmp(TopFrame, 2); 97295Seric } 98295Seric /* 99295Seric ** USRERR -- Signal user error. 100295Seric ** 101295Seric ** This is much like syserr except it is for user errors. 102295Seric ** 103295Seric ** Parameters: 104295Seric ** fmt, a, b, c, d -- printf strings 105295Seric ** 106295Seric ** Returns: 1074084Seric ** none 1087762Seric ** Through TopFrame if QuickAbort is set. 109295Seric ** 110295Seric ** Side Effects: 1111514Seric ** increments Errors. 112295Seric */ 113295Seric 114295Seric /*VARARGS1*/ 11557642Seric #ifdef __STDC__ 11657642Seric usrerr(char *fmt, ...) 11757642Seric #else 11857642Seric usrerr(fmt, va_alist) 119295Seric char *fmt; 12057642Seric va_dcl 12157642Seric #endif 122295Seric { 12356852Seric VA_LOCAL_DECL 124295Seric extern char SuprErrs; 12516901Seric extern int errno; 126295Seric 127295Seric if (SuprErrs) 1284084Seric return; 129295Seric 13056852Seric VA_START(fmt); 13158524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 13256852Seric VA_END; 1339389Seric puterrmsg(MsgBuf); 1348239Seric 13551951Seric # ifdef LOG 13658020Seric if (LogLevel > 3 && LogUsrErrs) 13751951Seric syslog(LOG_NOTICE, "%s: %s", 13851951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 13951951Seric &MsgBuf[4]); 14056795Seric # endif /* LOG */ 14151951Seric 1427762Seric if (QuickAbort) 1437762Seric longjmp(TopFrame, 1); 1444063Seric } 1454063Seric /* 1464063Seric ** MESSAGE -- print message (not necessarily an error) 1474063Seric ** 1484063Seric ** Parameters: 1494063Seric ** num -- the default ARPANET error number (in ascii) 1504063Seric ** msg -- the message (printf fmt) -- if it begins 1514063Seric ** with a digit, this number overrides num. 1524063Seric ** a, b, c, d, e -- printf arguments 1534063Seric ** 1544063Seric ** Returns: 1554063Seric ** none 1564063Seric ** 1574063Seric ** Side Effects: 1584063Seric ** none. 1594063Seric */ 1604063Seric 1614084Seric /*VARARGS2*/ 16257642Seric #ifdef __STDC__ 16358151Seric message(char *msg, ...) 16457642Seric #else 16558151Seric message(msg, va_alist) 16656852Seric char *msg; 16757642Seric va_dcl 16857642Seric #endif 1694063Seric { 17056852Seric VA_LOCAL_DECL 17156852Seric 1724711Seric errno = 0; 17356852Seric VA_START(msg); 17458151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 17556852Seric VA_END; 1769108Seric putmsg(MsgBuf, FALSE); 1777613Seric } 1787613Seric /* 1798239Seric ** NMESSAGE -- print message (not necessarily an error) 1808239Seric ** 1818239Seric ** Just like "message" except it never puts the to... tag on. 1828239Seric ** 1838239Seric ** Parameters: 1848239Seric ** num -- the default ARPANET error number (in ascii) 1858239Seric ** msg -- the message (printf fmt) -- if it begins 18624943Seric ** with three digits, this number overrides num. 1878239Seric ** a, b, c, d, e -- printf arguments 1888239Seric ** 1898239Seric ** Returns: 1908239Seric ** none 1918239Seric ** 1928239Seric ** Side Effects: 1938239Seric ** none. 1948239Seric */ 1958239Seric 1968239Seric /*VARARGS2*/ 19757642Seric #ifdef __STDC__ 19858151Seric nmessage(char *msg, ...) 19957642Seric #else 20058151Seric nmessage(msg, va_alist) 20156852Seric char *msg; 20257642Seric va_dcl 20357642Seric #endif 2048239Seric { 20556852Seric VA_LOCAL_DECL 20656852Seric 2078239Seric errno = 0; 20856852Seric VA_START(msg); 20958151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 21056852Seric VA_END; 2119108Seric putmsg(MsgBuf, FALSE); 2128239Seric } 2138239Seric /* 2147613Seric ** PUTMSG -- output error message to transcript and channel 2157613Seric ** 2167613Seric ** Parameters: 2177613Seric ** msg -- message to output (in SMTP format). 2189108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2199108Seric ** our output channel. 2207613Seric ** 2217613Seric ** Returns: 2227613Seric ** none. 2237613Seric ** 2247613Seric ** Side Effects: 2257613Seric ** Outputs msg to the transcript. 2267613Seric ** If appropriate, outputs it to the channel. 2277613Seric ** Deletes SMTP reply code number as appropriate. 2287613Seric */ 2294711Seric 2309108Seric putmsg(msg, holdmsg) 2317613Seric char *msg; 2329108Seric bool holdmsg; 2337613Seric { 23414900Seric /* output to transcript if serious */ 23514900Seric if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5')) 23614900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2374711Seric 2384711Seric /* output to channel if appropriate */ 2399108Seric if (!holdmsg && (Verbose || msg[0] != '0')) 2404063Seric { 2417275Seric (void) fflush(stdout); 24252220Seric if (OpMode == MD_SMTP) 2437613Seric fprintf(OutChannel, "%s\r\n", msg); 2444711Seric else 2457613Seric fprintf(OutChannel, "%s\n", &msg[4]); 2464711Seric (void) fflush(OutChannel); 2474063Seric } 2489389Seric } 2499389Seric /* 2509389Seric ** PUTERRMSG -- like putmsg, but does special processing for error messages 2519389Seric ** 2529389Seric ** Parameters: 2539389Seric ** msg -- the message to output. 2549389Seric ** 2559389Seric ** Returns: 2569389Seric ** none. 2579389Seric ** 2589389Seric ** Side Effects: 2599389Seric ** Sets the fatal error bit in the envelope as appropriate. 2609389Seric */ 2618239Seric 2629389Seric puterrmsg(msg) 2639389Seric char *msg; 2649389Seric { 2659389Seric /* output the message as usual */ 2669389Seric putmsg(msg, HoldErrs); 2679389Seric 2689389Seric /* signal the error */ 2699389Seric Errors++; 2709389Seric if (msg[0] == '5') 2719336Seric CurEnv->e_flags |= EF_FATALERRS; 2724711Seric } 2734711Seric /* 2744711Seric ** FMTMSG -- format a message into buffer. 2754711Seric ** 2764711Seric ** Parameters: 2774711Seric ** eb -- error buffer to get result. 2784711Seric ** to -- the recipient tag for this message. 2794711Seric ** num -- arpanet error number. 28016901Seric ** en -- the error number to display. 2814711Seric ** fmt -- format of string. 2824711Seric ** a, b, c, d, e -- arguments. 2834711Seric ** 2844711Seric ** Returns: 2854711Seric ** none. 2864711Seric ** 2874711Seric ** Side Effects: 2884711Seric ** none. 2894711Seric */ 2904063Seric 29146928Sbostic static void 29256852Seric fmtmsg(eb, to, num, eno, fmt, ap) 2934711Seric register char *eb; 2944711Seric char *to; 2954711Seric char *num; 29616904Seric int eno; 2974711Seric char *fmt; 29856852Seric va_list ap; 2994711Seric { 3004711Seric char del; 3014711Seric 3024711Seric /* output the reply code */ 30324943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3044577Seric { 3054711Seric num = fmt; 3064711Seric fmt += 4; 3074711Seric } 3084711Seric if (num[3] == '-') 3094711Seric del = '-'; 3104711Seric else 3114711Seric del = ' '; 3124711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3134711Seric eb += 4; 3144063Seric 3159372Seric /* output the file name and line number */ 3169372Seric if (FileName != NULL) 3179372Seric { 3189372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3199372Seric eb += strlen(eb); 3209372Seric } 3219372Seric 3224711Seric /* output the "to" person */ 3234711Seric if (to != NULL && to[0] != '\0') 3244711Seric { 3254711Seric (void) sprintf(eb, "%s... ", to); 3265201Seric while (*eb != '\0') 3275201Seric *eb++ &= 0177; 3284711Seric } 3294711Seric 3304711Seric /* output the message */ 33156852Seric (void) vsprintf(eb, fmt, ap); 3325201Seric while (*eb != '\0') 3335201Seric *eb++ &= 0177; 3344711Seric 3354711Seric /* output the error code, if any */ 33616904Seric if (eno != 0) 3374711Seric { 33815136Seric extern char *errstring(); 33915136Seric 34016904Seric (void) sprintf(eb, ": %s", errstring(eno)); 3414711Seric eb += strlen(eb); 3424577Seric } 343295Seric } 34415136Seric /* 34515136Seric ** ERRSTRING -- return string description of error code 34615136Seric ** 34715136Seric ** Parameters: 34815136Seric ** errno -- the error number to translate 34915136Seric ** 35015136Seric ** Returns: 35115136Seric ** A string description of errno. 35215136Seric ** 35315136Seric ** Side Effects: 35415136Seric ** none. 35515136Seric */ 35615136Seric 35715136Seric char * 35815136Seric errstring(errno) 35915136Seric int errno; 36015136Seric { 36115136Seric extern char *sys_errlist[]; 36215136Seric extern int sys_nerr; 36357232Seric static char buf[MAXLINE]; 36424943Seric # ifdef SMTP 36524943Seric extern char *SmtpPhase; 36656795Seric # endif /* SMTP */ 36715136Seric 36824943Seric # ifdef DAEMON 36952107Seric # ifdef ETIMEDOUT 37024943Seric /* 37124943Seric ** Handle special network error codes. 37224943Seric ** 37324943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 37424943Seric */ 37524943Seric 37624943Seric switch (errno) 37724943Seric { 37824943Seric case ETIMEDOUT: 37924943Seric case ECONNRESET: 38024943Seric (void) strcpy(buf, sys_errlist[errno]); 38124943Seric if (SmtpPhase != NULL) 38224943Seric { 38324943Seric (void) strcat(buf, " during "); 38424943Seric (void) strcat(buf, SmtpPhase); 38524943Seric } 38625050Seric if (CurHostName != NULL) 38724943Seric { 38824943Seric (void) strcat(buf, " with "); 38925050Seric (void) strcat(buf, CurHostName); 39024943Seric } 39124943Seric return (buf); 39224943Seric 39324943Seric case EHOSTDOWN: 39425050Seric if (CurHostName == NULL) 39524943Seric break; 39625050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 39724943Seric return (buf); 39824943Seric 39924943Seric case ECONNREFUSED: 40025050Seric if (CurHostName == NULL) 40124943Seric break; 40225050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 40324943Seric return (buf); 40425526Smiriam 40557736Seric # ifdef NAMED_BIND 40658010Seric case HOST_NOT_FOUND + MAX_ERRNO: 40758010Seric return ("Name server: host not found"); 40858010Seric 40958010Seric case TRY_AGAIN + MAX_ERRNO: 41058010Seric return ("Name server: host name lookup failure"); 41158010Seric 41258010Seric case NO_RECOVERY + MAX_ERRNO: 41358010Seric return ("Name server: non-recoverable error"); 41458010Seric 41558010Seric case NO_DATA + MAX_ERRNO: 41658010Seric return ("Name server: no data known for name"); 41757736Seric # endif 41824943Seric } 41952107Seric # endif 42052107Seric # endif 42124943Seric 42215136Seric if (errno > 0 && errno < sys_nerr) 42315136Seric return (sys_errlist[errno]); 42415136Seric 42515136Seric (void) sprintf(buf, "Error %d", errno); 42615136Seric return (buf); 42715136Seric } 428