xref: /csrg-svn/usr.sbin/sendmail/src/err.c (revision 63839)
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*63839Seric static char sccsid[] = "@(#)err.c	8.3 (Berkeley) 07/16/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 */
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 */
24360421Seric 	if (holdmsg || (!Verbose && msg[0] == '0'))
24460421Seric 		return;
24560421Seric 
24660421Seric 	(void) fflush(stdout);
24760421Seric 	if (OpMode == MD_SMTP)
24860421Seric 		fprintf(OutChannel, "%s\r\n", msg);
24960421Seric 	else
25060421Seric 		fprintf(OutChannel, "%s\n", &msg[4]);
25163753Seric 	if (TrafficLogFile != NULL)
25263753Seric 		fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(),
25363753Seric 			OpMode == MD_SMTP ? msg : &msg[4]);
25460421Seric 	if (msg[3] == ' ')
25560421Seric 		(void) fflush(OutChannel);
25660421Seric 	if (!ferror(OutChannel))
25760421Seric 		return;
25860421Seric 
25960421Seric 	/* error on output -- if reporting lost channel, just ignore it */
26060421Seric 	if (feof(InChannel) || ferror(InChannel))
26160421Seric 		return;
26260421Seric 
26360421Seric 	/* can't call syserr, 'cause we are using MsgBuf */
26460421Seric 	HoldErrs = TRUE;
26560283Seric #ifdef LOG
26660421Seric 	if (LogLevel > 0)
26760421Seric 		syslog(LOG_CRIT,
26863753Seric 			"%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"",
26960421Seric 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
27060421Seric 			CurHostName, msg);
27160283Seric #endif
2729389Seric }
2739389Seric /*
27463753Seric **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
2759389Seric **
2769389Seric **	Parameters:
2779389Seric **		msg -- the message to output.
2789389Seric **
2799389Seric **	Returns:
2809389Seric **		none.
2819389Seric **
2829389Seric **	Side Effects:
2839389Seric **		Sets the fatal error bit in the envelope as appropriate.
2849389Seric */
2858239Seric 
2869389Seric puterrmsg(msg)
2879389Seric 	char *msg;
2889389Seric {
2899389Seric 	/* output the message as usual */
29063753Seric 	putoutmsg(msg, HoldErrs);
2919389Seric 
2929389Seric 	/* signal the error */
2939389Seric 	Errors++;
294*63839Seric 	if (msg[0] == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
2959336Seric 		CurEnv->e_flags |= EF_FATALERRS;
2964711Seric }
2974711Seric /*
2984711Seric **  FMTMSG -- format a message into buffer.
2994711Seric **
3004711Seric **	Parameters:
3014711Seric **		eb -- error buffer to get result.
3024711Seric **		to -- the recipient tag for this message.
3034711Seric **		num -- arpanet error number.
30416901Seric **		en -- the error number to display.
3054711Seric **		fmt -- format of string.
3064711Seric **		a, b, c, d, e -- arguments.
3074711Seric **
3084711Seric **	Returns:
3094711Seric **		none.
3104711Seric **
3114711Seric **	Side Effects:
3124711Seric **		none.
3134711Seric */
3144063Seric 
31546928Sbostic static void
31656852Seric fmtmsg(eb, to, num, eno, fmt, ap)
3174711Seric 	register char *eb;
3184711Seric 	char *to;
3194711Seric 	char *num;
32016904Seric 	int eno;
3214711Seric 	char *fmt;
32256852Seric 	va_list ap;
3234711Seric {
3244711Seric 	char del;
32559596Seric 	char *meb;
3264711Seric 
3274711Seric 	/* output the reply code */
32824943Seric 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
3294577Seric 	{
3304711Seric 		num = fmt;
3314711Seric 		fmt += 4;
3324711Seric 	}
3334711Seric 	if (num[3] == '-')
3344711Seric 		del = '-';
3354711Seric 	else
3364711Seric 		del = ' ';
3374711Seric 	(void) sprintf(eb, "%3.3s%c", num, del);
3384711Seric 	eb += 4;
3394063Seric 
3409372Seric 	/* output the file name and line number */
3419372Seric 	if (FileName != NULL)
3429372Seric 	{
3439372Seric 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
3449372Seric 		eb += strlen(eb);
3459372Seric 	}
3469372Seric 
3474711Seric 	/* output the "to" person */
3484711Seric 	if (to != NULL && to[0] != '\0')
3494711Seric 	{
3504711Seric 		(void) sprintf(eb, "%s... ", to);
3515201Seric 		while (*eb != '\0')
3525201Seric 			*eb++ &= 0177;
3534711Seric 	}
3544711Seric 
35559596Seric 	meb = eb;
35659596Seric 
3574711Seric 	/* output the message */
35856852Seric 	(void) vsprintf(eb, fmt, ap);
3595201Seric 	while (*eb != '\0')
3605201Seric 		*eb++ &= 0177;
3614711Seric 
3624711Seric 	/* output the error code, if any */
36316904Seric 	if (eno != 0)
3644711Seric 	{
36516904Seric 		(void) sprintf(eb, ": %s", errstring(eno));
3664711Seric 		eb += strlen(eb);
3674577Seric 	}
36859596Seric 
36959734Seric 	if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL)
37059596Seric 		CurEnv->e_message = newstr(meb);
371295Seric }
37215136Seric /*
37315136Seric **  ERRSTRING -- return string description of error code
37415136Seric **
37515136Seric **	Parameters:
37615136Seric **		errno -- the error number to translate
37715136Seric **
37815136Seric **	Returns:
37915136Seric **		A string description of errno.
38015136Seric **
38115136Seric **	Side Effects:
38215136Seric **		none.
38315136Seric */
38415136Seric 
38560089Seric const char *
38615136Seric errstring(errno)
38715136Seric 	int errno;
38815136Seric {
389*63839Seric 	static char buf[MAXLINE];
390*63839Seric # ifndef ERRLIST_PREDEFINED
391*63839Seric 	extern char *sys_errlist[];
39215136Seric 	extern int sys_nerr;
393*63839Seric # endif
39424943Seric # ifdef SMTP
39524943Seric 	extern char *SmtpPhase;
39656795Seric # endif /* SMTP */
39715136Seric 
39824943Seric # ifdef DAEMON
39952107Seric # ifdef ETIMEDOUT
40024943Seric 	/*
40124943Seric 	**  Handle special network error codes.
40224943Seric 	**
40324943Seric 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
40424943Seric 	*/
40524943Seric 
40624943Seric 	switch (errno)
40724943Seric 	{
40824943Seric 	  case ETIMEDOUT:
40924943Seric 	  case ECONNRESET:
41024943Seric 		(void) strcpy(buf, sys_errlist[errno]);
41124943Seric 		if (SmtpPhase != NULL)
41224943Seric 		{
41324943Seric 			(void) strcat(buf, " during ");
41424943Seric 			(void) strcat(buf, SmtpPhase);
41524943Seric 		}
41625050Seric 		if (CurHostName != NULL)
41724943Seric 		{
41824943Seric 			(void) strcat(buf, " with ");
41925050Seric 			(void) strcat(buf, CurHostName);
42024943Seric 		}
42124943Seric 		return (buf);
42224943Seric 
42324943Seric 	  case EHOSTDOWN:
42425050Seric 		if (CurHostName == NULL)
42524943Seric 			break;
42625050Seric 		(void) sprintf(buf, "Host %s is down", CurHostName);
42724943Seric 		return (buf);
42824943Seric 
42924943Seric 	  case ECONNREFUSED:
43025050Seric 		if (CurHostName == NULL)
43124943Seric 			break;
43225050Seric 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
43324943Seric 		return (buf);
43425526Smiriam 
43557736Seric # ifdef NAMED_BIND
43658010Seric 	  case HOST_NOT_FOUND + MAX_ERRNO:
43758010Seric 		return ("Name server: host not found");
43858010Seric 
43958010Seric 	  case TRY_AGAIN + MAX_ERRNO:
44058010Seric 		return ("Name server: host name lookup failure");
44158010Seric 
44258010Seric 	  case NO_RECOVERY + MAX_ERRNO:
44358010Seric 		return ("Name server: non-recoverable error");
44458010Seric 
44558010Seric 	  case NO_DATA + MAX_ERRNO:
44658010Seric 		return ("Name server: no data known for name");
44757736Seric # endif
44824943Seric 	}
44952107Seric # endif
45052107Seric # endif
45124943Seric 
45215136Seric 	if (errno > 0 && errno < sys_nerr)
45315136Seric 		return (sys_errlist[errno]);
45415136Seric 
45515136Seric 	(void) sprintf(buf, "Error %d", errno);
45615136Seric 	return (buf);
45715136Seric }
458