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*64725Seric static char sccsid[] = "@(#)err.c 8.11 (Berkeley) 10/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 4363969Seric static void fmtmsg(); 4446928Sbostic 4563969Seric #if defined(NAMED_BIND) && !defined(NO_DATA) 4663969Seric # define NO_DATA NO_ADDRESS 4763969Seric #endif 4863969Seric 4958824Seric void 50295Seric /*VARARGS1*/ 5157642Seric #ifdef __STDC__ 5260094Seric syserr(const char *fmt, ...) 5357642Seric #else 5457642Seric syserr(fmt, va_alist) 5560094Seric const 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 */ 93*64725Seric if (olderrno == EMFILE) 94*64725Seric printopenfds(TRUE); 9558690Seric if (panic) 9659156Seric { 9759156Seric #ifdef XLA 9859156Seric xla_all_end(); 9959156Seric #endif 10058690Seric exit(EX_OSERR); 10159156Seric } 102295Seric errno = 0; 1037762Seric if (QuickAbort) 1047762Seric longjmp(TopFrame, 2); 105295Seric } 106295Seric /* 107295Seric ** USRERR -- Signal user error. 108295Seric ** 109295Seric ** This is much like syserr except it is for user errors. 110295Seric ** 111295Seric ** Parameters: 112295Seric ** fmt, a, b, c, d -- printf strings 113295Seric ** 114295Seric ** Returns: 1154084Seric ** none 1167762Seric ** Through TopFrame if QuickAbort is set. 117295Seric ** 118295Seric ** Side Effects: 1191514Seric ** increments Errors. 120295Seric */ 121295Seric 122295Seric /*VARARGS1*/ 12358824Seric void 12457642Seric #ifdef __STDC__ 12560094Seric usrerr(const char *fmt, ...) 12657642Seric #else 12757642Seric usrerr(fmt, va_alist) 12860094Seric const char *fmt; 12957642Seric va_dcl 13057642Seric #endif 131295Seric { 13256852Seric VA_LOCAL_DECL 133295Seric extern char SuprErrs; 13416901Seric extern int errno; 135295Seric 136295Seric if (SuprErrs) 1374084Seric return; 138295Seric 13956852Seric VA_START(fmt); 14058524Seric fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 14156852Seric VA_END; 1429389Seric puterrmsg(MsgBuf); 1438239Seric 14451951Seric # ifdef LOG 14558020Seric if (LogLevel > 3 && LogUsrErrs) 14651951Seric syslog(LOG_NOTICE, "%s: %s", 14751951Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 14851951Seric &MsgBuf[4]); 14956795Seric # endif /* LOG */ 15051951Seric 1517762Seric if (QuickAbort) 1527762Seric longjmp(TopFrame, 1); 1534063Seric } 1544063Seric /* 1554063Seric ** MESSAGE -- print message (not necessarily an error) 1564063Seric ** 1574063Seric ** Parameters: 15859581Seric ** msg -- the message (printf fmt) -- it can begin with 15959581Seric ** an SMTP reply code. If not, 050 is assumed. 1604063Seric ** a, b, c, d, e -- printf arguments 1614063Seric ** 1624063Seric ** Returns: 1634063Seric ** none 1644063Seric ** 1654063Seric ** Side Effects: 1664063Seric ** none. 1674063Seric */ 1684063Seric 1694084Seric /*VARARGS2*/ 17058826Seric void 17157642Seric #ifdef __STDC__ 17260094Seric message(const char *msg, ...) 17357642Seric #else 17458151Seric message(msg, va_alist) 17560094Seric const char *msg; 17657642Seric va_dcl 17757642Seric #endif 1784063Seric { 17956852Seric VA_LOCAL_DECL 18056852Seric 1814711Seric errno = 0; 18256852Seric VA_START(msg); 18358151Seric fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 18456852Seric VA_END; 18563753Seric putoutmsg(MsgBuf, FALSE); 1867613Seric } 1877613Seric /* 1888239Seric ** NMESSAGE -- print message (not necessarily an error) 1898239Seric ** 1908239Seric ** Just like "message" except it never puts the to... tag on. 1918239Seric ** 1928239Seric ** Parameters: 1938239Seric ** num -- the default ARPANET error number (in ascii) 1948239Seric ** msg -- the message (printf fmt) -- if it begins 19524943Seric ** with three digits, this number overrides num. 1968239Seric ** a, b, c, d, e -- printf arguments 1978239Seric ** 1988239Seric ** Returns: 1998239Seric ** none 2008239Seric ** 2018239Seric ** Side Effects: 2028239Seric ** none. 2038239Seric */ 2048239Seric 2058239Seric /*VARARGS2*/ 20658826Seric void 20757642Seric #ifdef __STDC__ 20860094Seric nmessage(const char *msg, ...) 20957642Seric #else 21058151Seric nmessage(msg, va_alist) 21160094Seric const char *msg; 21257642Seric va_dcl 21357642Seric #endif 2148239Seric { 21556852Seric VA_LOCAL_DECL 21656852Seric 2178239Seric errno = 0; 21856852Seric VA_START(msg); 21958151Seric fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 22056852Seric VA_END; 22163753Seric putoutmsg(MsgBuf, FALSE); 2228239Seric } 2238239Seric /* 22463753Seric ** PUTOUTMSG -- output error message to transcript and channel 2257613Seric ** 2267613Seric ** Parameters: 2277613Seric ** msg -- message to output (in SMTP format). 2289108Seric ** holdmsg -- if TRUE, don't output a copy of the message to 2299108Seric ** our output channel. 2307613Seric ** 2317613Seric ** Returns: 2327613Seric ** none. 2337613Seric ** 2347613Seric ** Side Effects: 2357613Seric ** Outputs msg to the transcript. 2367613Seric ** If appropriate, outputs it to the channel. 2377613Seric ** Deletes SMTP reply code number as appropriate. 2387613Seric */ 2394711Seric 24063753Seric putoutmsg(msg, holdmsg) 2417613Seric char *msg; 2429108Seric bool holdmsg; 2437613Seric { 24464249Seric /* display for debugging */ 24564249Seric if (tTd(54, 8)) 24664249Seric printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); 24764249Seric 24814900Seric /* output to transcript if serious */ 24963848Seric if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) 25014900Seric fprintf(CurEnv->e_xfp, "%s\n", msg); 2514711Seric 2524711Seric /* output to channel if appropriate */ 25360421Seric if (holdmsg || (!Verbose && msg[0] == '0')) 25460421Seric return; 25560421Seric 25663848Seric /* map warnings to something SMTP can handle */ 25763848Seric if (msg[0] == '6') 25863848Seric msg[0] = '5'; 25963848Seric 26060421Seric (void) fflush(stdout); 26160421Seric if (OpMode == MD_SMTP) 26260421Seric fprintf(OutChannel, "%s\r\n", msg); 26360421Seric else 26460421Seric fprintf(OutChannel, "%s\n", &msg[4]); 26563753Seric if (TrafficLogFile != NULL) 26663753Seric fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 26763753Seric OpMode == MD_SMTP ? msg : &msg[4]); 26860421Seric if (msg[3] == ' ') 26960421Seric (void) fflush(OutChannel); 27060421Seric if (!ferror(OutChannel)) 27160421Seric return; 27260421Seric 27364499Seric /* 27464499Seric ** Error on output -- if reporting lost channel, just ignore it. 27564499Seric ** Also, ignore errors from QUIT response (221 message) -- some 27664499Seric ** rude servers don't read result. 27764499Seric */ 27864499Seric 27964499Seric if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0) 28060421Seric return; 28160421Seric 28260421Seric /* can't call syserr, 'cause we are using MsgBuf */ 28360421Seric HoldErrs = TRUE; 28460283Seric #ifdef LOG 28560421Seric if (LogLevel > 0) 28660421Seric syslog(LOG_CRIT, 28764499Seric "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %m", 28860421Seric CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 28964123Seric CurHostName == NULL ? "NO-HOST" : CurHostName, 29064123Seric msg); 29160283Seric #endif 2929389Seric } 2939389Seric /* 29463753Seric ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 2959389Seric ** 2969389Seric ** Parameters: 2979389Seric ** msg -- the message to output. 2989389Seric ** 2999389Seric ** Returns: 3009389Seric ** none. 3019389Seric ** 3029389Seric ** Side Effects: 3039389Seric ** Sets the fatal error bit in the envelope as appropriate. 3049389Seric */ 3058239Seric 3069389Seric puterrmsg(msg) 3079389Seric char *msg; 3089389Seric { 30963848Seric char msgcode = msg[0]; 31063848Seric 3119389Seric /* output the message as usual */ 31263753Seric putoutmsg(msg, HoldErrs); 3139389Seric 3149389Seric /* signal the error */ 31563848Seric if (msgcode == '6') 31663848Seric { 31763848Seric /* notify the postmaster */ 31863848Seric CurEnv->e_flags |= EF_PM_NOTIFY; 31963848Seric } 32063848Seric else 32163848Seric { 32263848Seric Errors++; 32363848Seric if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 32463848Seric CurEnv->e_flags |= EF_FATALERRS; 32563848Seric } 3264711Seric } 3274711Seric /* 3284711Seric ** FMTMSG -- format a message into buffer. 3294711Seric ** 3304711Seric ** Parameters: 3314711Seric ** eb -- error buffer to get result. 3324711Seric ** to -- the recipient tag for this message. 3334711Seric ** num -- arpanet error number. 33416901Seric ** en -- the error number to display. 3354711Seric ** fmt -- format of string. 3364711Seric ** a, b, c, d, e -- arguments. 3374711Seric ** 3384711Seric ** Returns: 3394711Seric ** none. 3404711Seric ** 3414711Seric ** Side Effects: 3424711Seric ** none. 3434711Seric */ 3444063Seric 34546928Sbostic static void 34656852Seric fmtmsg(eb, to, num, eno, fmt, ap) 3474711Seric register char *eb; 3484711Seric char *to; 3494711Seric char *num; 35016904Seric int eno; 3514711Seric char *fmt; 35256852Seric va_list ap; 3534711Seric { 3544711Seric char del; 35559596Seric char *meb; 3564711Seric 3574711Seric /* output the reply code */ 35824943Seric if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 3594577Seric { 3604711Seric num = fmt; 3614711Seric fmt += 4; 3624711Seric } 3634711Seric if (num[3] == '-') 3644711Seric del = '-'; 3654711Seric else 3664711Seric del = ' '; 3674711Seric (void) sprintf(eb, "%3.3s%c", num, del); 3684711Seric eb += 4; 3694063Seric 3709372Seric /* output the file name and line number */ 3719372Seric if (FileName != NULL) 3729372Seric { 3739372Seric (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 3749372Seric eb += strlen(eb); 3759372Seric } 3769372Seric 3774711Seric /* output the "to" person */ 3784711Seric if (to != NULL && to[0] != '\0') 3794711Seric { 3804711Seric (void) sprintf(eb, "%s... ", to); 3815201Seric while (*eb != '\0') 3825201Seric *eb++ &= 0177; 3834711Seric } 3844711Seric 38559596Seric meb = eb; 38659596Seric 3874711Seric /* output the message */ 38856852Seric (void) vsprintf(eb, fmt, ap); 3895201Seric while (*eb != '\0') 3905201Seric *eb++ &= 0177; 3914711Seric 3924711Seric /* output the error code, if any */ 39316904Seric if (eno != 0) 3944711Seric { 39516904Seric (void) sprintf(eb, ": %s", errstring(eno)); 3964711Seric eb += strlen(eb); 3974577Seric } 39859596Seric 39964695Seric if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) 40064695Seric { 40164695Seric if (CurEnv->e_message != NULL) 40264695Seric free(CurEnv->e_message); 40359596Seric CurEnv->e_message = newstr(meb); 40464695Seric } 405295Seric } 40615136Seric /* 40715136Seric ** ERRSTRING -- return string description of error code 40815136Seric ** 40915136Seric ** Parameters: 41015136Seric ** errno -- the error number to translate 41115136Seric ** 41215136Seric ** Returns: 41315136Seric ** A string description of errno. 41415136Seric ** 41515136Seric ** Side Effects: 41615136Seric ** none. 41715136Seric */ 41815136Seric 41960089Seric const char * 42015136Seric errstring(errno) 42115136Seric int errno; 42215136Seric { 42363839Seric static char buf[MAXLINE]; 42463839Seric # ifndef ERRLIST_PREDEFINED 42563839Seric extern char *sys_errlist[]; 42615136Seric extern int sys_nerr; 42763839Seric # endif 42824943Seric # ifdef SMTP 42924943Seric extern char *SmtpPhase; 43056795Seric # endif /* SMTP */ 43115136Seric 43224943Seric # ifdef DAEMON 43352107Seric # ifdef ETIMEDOUT 43424943Seric /* 43524943Seric ** Handle special network error codes. 43624943Seric ** 43724943Seric ** These are 4.2/4.3bsd specific; they should be in daemon.c. 43824943Seric */ 43924943Seric 44024943Seric switch (errno) 44124943Seric { 44224943Seric case ETIMEDOUT: 44324943Seric case ECONNRESET: 44424943Seric (void) strcpy(buf, sys_errlist[errno]); 44524943Seric if (SmtpPhase != NULL) 44624943Seric { 44724943Seric (void) strcat(buf, " during "); 44824943Seric (void) strcat(buf, SmtpPhase); 44924943Seric } 45025050Seric if (CurHostName != NULL) 45124943Seric { 45224943Seric (void) strcat(buf, " with "); 45325050Seric (void) strcat(buf, CurHostName); 45424943Seric } 45524943Seric return (buf); 45624943Seric 45724943Seric case EHOSTDOWN: 45825050Seric if (CurHostName == NULL) 45924943Seric break; 46025050Seric (void) sprintf(buf, "Host %s is down", CurHostName); 46124943Seric return (buf); 46224943Seric 46324943Seric case ECONNREFUSED: 46425050Seric if (CurHostName == NULL) 46524943Seric break; 46625050Seric (void) sprintf(buf, "Connection refused by %s", CurHostName); 46724943Seric return (buf); 46825526Smiriam 46963993Seric case EOPENTIMEOUT: 47063993Seric return "Timeout on file open"; 47163993Seric 47257736Seric # ifdef NAMED_BIND 47363993Seric case HOST_NOT_FOUND + E_DNSBASE: 47458010Seric return ("Name server: host not found"); 47558010Seric 47663993Seric case TRY_AGAIN + E_DNSBASE: 47758010Seric return ("Name server: host name lookup failure"); 47858010Seric 47963993Seric case NO_RECOVERY + E_DNSBASE: 48058010Seric return ("Name server: non-recoverable error"); 48158010Seric 48263993Seric case NO_DATA + E_DNSBASE: 48358010Seric return ("Name server: no data known for name"); 48457736Seric # endif 48524943Seric } 48652107Seric # endif 48752107Seric # endif 48824943Seric 48915136Seric if (errno > 0 && errno < sys_nerr) 49015136Seric return (sys_errlist[errno]); 49115136Seric 49215136Seric (void) sprintf(buf, "Error %d", errno); 49315136Seric return (buf); 49415136Seric } 495