xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 60421)
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*60421Seric static char sccsid[] = "@(#)err.c	6.23 (Berkeley) 05/25/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__
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 */
9358690Seric 	if (panic)
9459156Seric 	{
9559156Seric #ifdef XLA
9659156Seric 		xla_all_end();
9759156Seric #endif
9858690Seric 		exit(EX_OSERR);
9959156Seric 	}
100295Seric 	errno = 0;
1017762Seric 	if (QuickAbort)
1027762Seric 		longjmp(TopFrame, 2);
103295Seric }
104295Seric /*
105295Seric **  USRERR -- Signal user error.
106295Seric **
107295Seric **	This is much like syserr except it is for user errors.
108295Seric **
109295Seric **	Parameters:
110295Seric **		fmt, a, b, c, d -- printf strings
111295Seric **
112295Seric **	Returns:
1134084Seric **		none
1147762Seric **		Through TopFrame if QuickAbort is set.
115295Seric **
116295Seric **	Side Effects:
1171514Seric **		increments Errors.
118295Seric */
119295Seric 
120295Seric /*VARARGS1*/
12158824Seric void
12257642Seric #ifdef __STDC__
12360094Seric usrerr(const char *fmt, ...)
12457642Seric #else
12557642Seric usrerr(fmt, va_alist)
12660094Seric 	const char *fmt;
12757642Seric 	va_dcl
12857642Seric #endif
129295Seric {
13056852Seric 	VA_LOCAL_DECL
131295Seric 	extern char SuprErrs;
13216901Seric 	extern int errno;
133295Seric 
134295Seric 	if (SuprErrs)
1354084Seric 		return;
136295Seric 
13756852Seric 	VA_START(fmt);
13858524Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
13956852Seric 	VA_END;
1409389Seric 	puterrmsg(MsgBuf);
1418239Seric 
14251951Seric # ifdef LOG
14358020Seric 	if (LogLevel > 3 && LogUsrErrs)
14451951Seric 		syslog(LOG_NOTICE, "%s: %s",
14551951Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
14651951Seric 			&MsgBuf[4]);
14756795Seric # endif /* LOG */
14851951Seric 
1497762Seric 	if (QuickAbort)
1507762Seric 		longjmp(TopFrame, 1);
1514063Seric }
1524063Seric /*
1534063Seric **  MESSAGE -- print message (not necessarily an error)
1544063Seric **
1554063Seric **	Parameters:
15659581Seric **		msg -- the message (printf fmt) -- it can begin with
15759581Seric **			an SMTP reply code.  If not, 050 is assumed.
1584063Seric **		a, b, c, d, e -- printf arguments
1594063Seric **
1604063Seric **	Returns:
1614063Seric **		none
1624063Seric **
1634063Seric **	Side Effects:
1644063Seric **		none.
1654063Seric */
1664063Seric 
1674084Seric /*VARARGS2*/
16858826Seric void
16957642Seric #ifdef __STDC__
17060094Seric message(const char *msg, ...)
17157642Seric #else
17258151Seric message(msg, va_alist)
17360094Seric 	const char *msg;
17457642Seric 	va_dcl
17557642Seric #endif
1764063Seric {
17756852Seric 	VA_LOCAL_DECL
17856852Seric 
1794711Seric 	errno = 0;
18056852Seric 	VA_START(msg);
18158151Seric 	fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
18256852Seric 	VA_END;
1839108Seric 	putmsg(MsgBuf, FALSE);
1847613Seric }
1857613Seric /*
1868239Seric **  NMESSAGE -- print message (not necessarily an error)
1878239Seric **
1888239Seric **	Just like "message" except it never puts the to... tag on.
1898239Seric **
1908239Seric **	Parameters:
1918239Seric **		num -- the default ARPANET error number (in ascii)
1928239Seric **		msg -- the message (printf fmt) -- if it begins
19324943Seric **			with three digits, this number overrides num.
1948239Seric **		a, b, c, d, e -- printf arguments
1958239Seric **
1968239Seric **	Returns:
1978239Seric **		none
1988239Seric **
1998239Seric **	Side Effects:
2008239Seric **		none.
2018239Seric */
2028239Seric 
2038239Seric /*VARARGS2*/
20458826Seric void
20557642Seric #ifdef __STDC__
20660094Seric nmessage(const char *msg, ...)
20757642Seric #else
20858151Seric nmessage(msg, va_alist)
20960094Seric 	const char *msg;
21057642Seric 	va_dcl
21157642Seric #endif
2128239Seric {
21356852Seric 	VA_LOCAL_DECL
21456852Seric 
2158239Seric 	errno = 0;
21656852Seric 	VA_START(msg);
21758151Seric 	fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
21856852Seric 	VA_END;
2199108Seric 	putmsg(MsgBuf, FALSE);
2208239Seric }
2218239Seric /*
2227613Seric **  PUTMSG -- output error message to transcript and channel
2237613Seric **
2247613Seric **	Parameters:
2257613Seric **		msg -- message to output (in SMTP format).
2269108Seric **		holdmsg -- if TRUE, don't output a copy of the message to
2279108Seric **			our output channel.
2287613Seric **
2297613Seric **	Returns:
2307613Seric **		none.
2317613Seric **
2327613Seric **	Side Effects:
2337613Seric **		Outputs msg to the transcript.
2347613Seric **		If appropriate, outputs it to the channel.
2357613Seric **		Deletes SMTP reply code number as appropriate.
2367613Seric */
2374711Seric 
2389108Seric putmsg(msg, holdmsg)
2397613Seric 	char *msg;
2409108Seric 	bool holdmsg;
2417613Seric {
24214900Seric 	/* output to transcript if serious */
24314900Seric 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
24414900Seric 		fprintf(CurEnv->e_xfp, "%s\n", msg);
2454711Seric 
2464711Seric 	/* output to channel if appropriate */
247*60421Seric 	if (holdmsg || (!Verbose && msg[0] == '0'))
248*60421Seric 		return;
249*60421Seric 
250*60421Seric 	(void) fflush(stdout);
251*60421Seric 	if (OpMode == MD_SMTP)
252*60421Seric 		fprintf(OutChannel, "%s\r\n", msg);
253*60421Seric 	else
254*60421Seric 		fprintf(OutChannel, "%s\n", &msg[4]);
255*60421Seric 	if (msg[3] == ' ')
256*60421Seric 		(void) fflush(OutChannel);
257*60421Seric 	if (!ferror(OutChannel))
258*60421Seric 		return;
259*60421Seric 
260*60421Seric 	/* error on output -- if reporting lost channel, just ignore it */
261*60421Seric 	if (feof(InChannel) || ferror(InChannel))
262*60421Seric 		return;
263*60421Seric 
264*60421Seric 	/* can't call syserr, 'cause we are using MsgBuf */
265*60421Seric 	HoldErrs = TRUE;
26660283Seric #ifdef LOG
267*60421Seric 	if (LogLevel > 0)
268*60421Seric 		syslog(LOG_CRIT,
269*60421Seric 			"%s: SYSERR: putmsg (%s): error on output channel sending \"%s\"",
270*60421Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
271*60421Seric 			CurHostName, msg);
27260283Seric #endif
2739389Seric }
2749389Seric /*
2759389Seric **  PUTERRMSG -- like putmsg, but does special processing for error messages
2769389Seric **
2779389Seric **	Parameters:
2789389Seric **		msg -- the message to output.
2799389Seric **
2809389Seric **	Returns:
2819389Seric **		none.
2829389Seric **
2839389Seric **	Side Effects:
2849389Seric **		Sets the fatal error bit in the envelope as appropriate.
2859389Seric */
2868239Seric 
2879389Seric puterrmsg(msg)
2889389Seric 	char *msg;
2899389Seric {
2909389Seric 	/* output the message as usual */
2919389Seric 	putmsg(msg, HoldErrs);
2929389Seric 
2939389Seric 	/* signal the error */
2949389Seric 	Errors++;
2959389Seric 	if (msg[0] == '5')
2969336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2974711Seric }
2984711Seric /*
2994711Seric **  FMTMSG -- format a message into buffer.
3004711Seric **
3014711Seric **	Parameters:
3024711Seric **		eb -- error buffer to get result.
3034711Seric **		to -- the recipient tag for this message.
3044711Seric **		num -- arpanet error number.
30516901Seric **		en -- the error number to display.
3064711Seric **		fmt -- format of string.
3074711Seric **		a, b, c, d, e -- arguments.
3084711Seric **
3094711Seric **	Returns:
3104711Seric **		none.
3114711Seric **
3124711Seric **	Side Effects:
3134711Seric **		none.
3144711Seric */
3154063Seric 
31646928Sbostic static void
31756852Seric fmtmsg(eb, to, num, eno, fmt, ap)
3184711Seric 	register char *eb;
3194711Seric 	char *to;
3204711Seric 	char *num;
32116904Seric 	int eno;
3224711Seric 	char *fmt;
32356852Seric 	va_list ap;
3244711Seric {
3254711Seric 	char del;
32659596Seric 	char *meb;
3274711Seric 
3284711Seric 	/* output the reply code */
32924943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
3304577Seric 	{
3314711Seric 		num = fmt;
3324711Seric 		fmt += 4;
3334711Seric 	}
3344711Seric 	if (num[3] == '-')
3354711Seric 		del = '-';
3364711Seric 	else
3374711Seric 		del = ' ';
3384711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
3394711Seric 	eb += 4;
3404063Seric 
3419372Seric 	/* output the file name and line number */
3429372Seric 	if (FileName != NULL)
3439372Seric 	{
3449372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
3459372Seric 		eb += strlen(eb);
3469372Seric 	}
3479372Seric 
3484711Seric 	/* output the "to" person */
3494711Seric 	if (to != NULL && to[0] != '\0')
3504711Seric 	{
3514711Seric 		(void) sprintf(eb, "%s... ", to);
3525201Seric 		while (*eb != '\0')
3535201Seric 			*eb++ &= 0177;
3544711Seric 	}
3554711Seric 
35659596Seric 	meb = eb;
35759596Seric 
3584711Seric 	/* output the message */
35956852Seric 	(void) vsprintf(eb, fmt, ap);
3605201Seric 	while (*eb != '\0')
3615201Seric 		*eb++ &= 0177;
3624711Seric 
3634711Seric 	/* output the error code, if any */
36416904Seric 	if (eno != 0)
3654711Seric 	{
36616904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3674711Seric 		eb += strlen(eb);
3684577Seric 	}
36959596Seric 
37059734Seric 	if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL)
37159596Seric 		CurEnv->e_message = newstr(meb);
372295Seric }
37315136Seric /*
37415136Seric **  ERRSTRING -- return string description of error code
37515136Seric **
37615136Seric **	Parameters:
37715136Seric **		errno -- the error number to translate
37815136Seric **
37915136Seric **	Returns:
38015136Seric **		A string description of errno.
38115136Seric **
38215136Seric **	Side Effects:
38315136Seric **		none.
38415136Seric */
38515136Seric 
38660089Seric const char *
38715136Seric errstring(errno)
38815136Seric 	int errno;
38915136Seric {
39060089Seric 	extern const char *const sys_errlist[];
39115136Seric 	extern int sys_nerr;
39257232Seric 	static char buf[MAXLINE];
39324943Seric # ifdef SMTP
39424943Seric 	extern char *SmtpPhase;
39556795Seric # endif /* SMTP */
39615136Seric 
39724943Seric # ifdef DAEMON
39852107Seric # ifdef ETIMEDOUT
39924943Seric 	/*
40024943Seric 	**  Handle special network error codes.
40124943Seric 	**
40224943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
40324943Seric 	*/
40424943Seric 
40524943Seric 	switch (errno)
40624943Seric 	{
40724943Seric 	  case ETIMEDOUT:
40824943Seric 	  case ECONNRESET:
40924943Seric 		(void) strcpy(buf, sys_errlist[errno]);
41024943Seric 		if (SmtpPhase != NULL)
41124943Seric 		{
41224943Seric 			(void) strcat(buf, " during ");
41324943Seric 			(void) strcat(buf, SmtpPhase);
41424943Seric 		}
41525050Seric 		if (CurHostName != NULL)
41624943Seric 		{
41724943Seric 			(void) strcat(buf, " with ");
41825050Seric 			(void) strcat(buf, CurHostName);
41924943Seric 		}
42024943Seric 		return (buf);
42124943Seric 
42224943Seric 	  case EHOSTDOWN:
42325050Seric 		if (CurHostName == NULL)
42424943Seric 			break;
42525050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
42624943Seric 		return (buf);
42724943Seric 
42824943Seric 	  case ECONNREFUSED:
42925050Seric 		if (CurHostName == NULL)
43024943Seric 			break;
43125050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
43224943Seric 		return (buf);
43325526Smiriam 
43457736Seric # ifdef NAMED_BIND
43558010Seric 	  case HOST_NOT_FOUND + MAX_ERRNO:
43658010Seric 		return ("Name server: host not found");
43758010Seric 
43858010Seric 	  case TRY_AGAIN + MAX_ERRNO:
43958010Seric 		return ("Name server: host name lookup failure");
44058010Seric 
44158010Seric 	  case NO_RECOVERY + MAX_ERRNO:
44258010Seric 		return ("Name server: non-recoverable error");
44358010Seric 
44458010Seric 	  case NO_DATA + MAX_ERRNO:
44558010Seric 		return ("Name server: no data known for name");
44657736Seric # endif
44724943Seric 	}
44852107Seric # endif
44952107Seric # endif
45024943Seric 
45115136Seric 	if (errno > 0 && errno < sys_nerr)
45215136Seric 		return (sys_errlist[errno]);
45315136Seric 
45415136Seric 	(void) sprintf(buf, "Error %d", errno);
45515136Seric 	return (buf);
45615136Seric }
457