xref: /original-bsd/usr.sbin/sendmail/src/err.c (revision 609cdd5c)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)err.c	6.13 (Berkeley) 04/18/93";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 # include <errno.h>
15 # include <netdb.h>
16 
17 /*
18 **  SYSERR -- Print error message.
19 **
20 **	Prints an error message via printf to the diagnostic
21 **	output.  If LOG is defined, it logs it also.
22 **
23 **	If the first character of the syserr message is `!' it will
24 **	log this as an ALERT message and exit immediately.  This can
25 **	leave queue files in an indeterminate state, so it should not
26 **	be used lightly.
27 **
28 **	Parameters:
29 **		f -- the format string
30 **		a, b, c, d, e -- parameters
31 **
32 **	Returns:
33 **		none
34 **		Through TopFrame if QuickAbort is set.
35 **
36 **	Side Effects:
37 **		increments Errors.
38 **		sets ExitStat.
39 */
40 
41 # ifdef lint
42 int	sys_nerr;
43 char	*sys_errlist[];
44 # endif lint
45 char	MsgBuf[BUFSIZ*2];	/* text of most recent message */
46 
47 static void fmtmsg();
48 
49 void
50 /*VARARGS1*/
51 #ifdef __STDC__
52 syserr(char *fmt, ...)
53 #else
54 syserr(fmt, va_alist)
55 	char *fmt;
56 	va_dcl
57 #endif
58 {
59 	register char *p;
60 	int olderrno = errno;
61 	bool panic;
62 	VA_LOCAL_DECL
63 
64 	panic = *fmt == '!';
65 	if (panic)
66 		fmt++;
67 
68 	/* format and output the error message */
69 	if (olderrno == 0)
70 		p = "554";
71 	else
72 		p = "451";
73 	VA_START(fmt);
74 	fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
75 	VA_END;
76 	puterrmsg(MsgBuf);
77 
78 	/* determine exit status if not already set */
79 	if (ExitStat == EX_OK)
80 	{
81 		if (olderrno == 0)
82 			ExitStat = EX_SOFTWARE;
83 		else
84 			ExitStat = EX_OSERR;
85 	}
86 
87 # ifdef LOG
88 	if (LogLevel > 0)
89 		syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s",
90 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
91 			&MsgBuf[4]);
92 # endif /* LOG */
93 	if (panic)
94 	{
95 #ifdef XLA
96 		xla_all_end();
97 #endif
98 		exit(EX_OSERR);
99 	}
100 	errno = 0;
101 	if (QuickAbort)
102 		longjmp(TopFrame, 2);
103 }
104 /*
105 **  USRERR -- Signal user error.
106 **
107 **	This is much like syserr except it is for user errors.
108 **
109 **	Parameters:
110 **		fmt, a, b, c, d -- printf strings
111 **
112 **	Returns:
113 **		none
114 **		Through TopFrame if QuickAbort is set.
115 **
116 **	Side Effects:
117 **		increments Errors.
118 */
119 
120 /*VARARGS1*/
121 void
122 #ifdef __STDC__
123 usrerr(char *fmt, ...)
124 #else
125 usrerr(fmt, va_alist)
126 	char *fmt;
127 	va_dcl
128 #endif
129 {
130 	VA_LOCAL_DECL
131 	extern char SuprErrs;
132 	extern int errno;
133 
134 	if (SuprErrs)
135 		return;
136 
137 	VA_START(fmt);
138 	fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
139 	VA_END;
140 	puterrmsg(MsgBuf);
141 
142 # ifdef LOG
143 	if (LogLevel > 3 && LogUsrErrs)
144 		syslog(LOG_NOTICE, "%s: %s",
145 			CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
146 			&MsgBuf[4]);
147 # endif /* LOG */
148 
149 	if (QuickAbort)
150 		longjmp(TopFrame, 1);
151 }
152 /*
153 **  MESSAGE -- print message (not necessarily an error)
154 **
155 **	Parameters:
156 **		num -- the default ARPANET error number (in ascii)
157 **		msg -- the message (printf fmt) -- if it begins
158 **			with a digit, this number overrides num.
159 **		a, b, c, d, e -- printf arguments
160 **
161 **	Returns:
162 **		none
163 **
164 **	Side Effects:
165 **		none.
166 */
167 
168 /*VARARGS2*/
169 void
170 #ifdef __STDC__
171 message(char *msg, ...)
172 #else
173 message(msg, va_alist)
174 	char *msg;
175 	va_dcl
176 #endif
177 {
178 	VA_LOCAL_DECL
179 
180 	errno = 0;
181 	VA_START(msg);
182 	fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
183 	VA_END;
184 	putmsg(MsgBuf, FALSE);
185 }
186 /*
187 **  NMESSAGE -- print message (not necessarily an error)
188 **
189 **	Just like "message" except it never puts the to... tag on.
190 **
191 **	Parameters:
192 **		num -- the default ARPANET error number (in ascii)
193 **		msg -- the message (printf fmt) -- if it begins
194 **			with three digits, this number overrides num.
195 **		a, b, c, d, e -- printf arguments
196 **
197 **	Returns:
198 **		none
199 **
200 **	Side Effects:
201 **		none.
202 */
203 
204 /*VARARGS2*/
205 void
206 #ifdef __STDC__
207 nmessage(char *msg, ...)
208 #else
209 nmessage(msg, va_alist)
210 	char *msg;
211 	va_dcl
212 #endif
213 {
214 	VA_LOCAL_DECL
215 
216 	errno = 0;
217 	VA_START(msg);
218 	fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
219 	VA_END;
220 	putmsg(MsgBuf, FALSE);
221 }
222 /*
223 **  PUTMSG -- output error message to transcript and channel
224 **
225 **	Parameters:
226 **		msg -- message to output (in SMTP format).
227 **		holdmsg -- if TRUE, don't output a copy of the message to
228 **			our output channel.
229 **
230 **	Returns:
231 **		none.
232 **
233 **	Side Effects:
234 **		Outputs msg to the transcript.
235 **		If appropriate, outputs it to the channel.
236 **		Deletes SMTP reply code number as appropriate.
237 */
238 
239 putmsg(msg, holdmsg)
240 	char *msg;
241 	bool holdmsg;
242 {
243 	/* output to transcript if serious */
244 	if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5'))
245 		fprintf(CurEnv->e_xfp, "%s\n", msg);
246 
247 	/* output to channel if appropriate */
248 	if (!holdmsg && (Verbose || msg[0] != '0'))
249 	{
250 		(void) fflush(stdout);
251 		if (OpMode == MD_SMTP)
252 			fprintf(OutChannel, "%s\r\n", msg);
253 		else
254 			fprintf(OutChannel, "%s\n", &msg[4]);
255 		(void) fflush(OutChannel);
256 		if (ferror(OutChannel))
257 		{
258 			HoldErrs = TRUE;
259 			syserr("putmsg: error on output channel");
260 		}
261 	}
262 }
263 /*
264 **  PUTERRMSG -- like putmsg, but does special processing for error messages
265 **
266 **	Parameters:
267 **		msg -- the message to output.
268 **
269 **	Returns:
270 **		none.
271 **
272 **	Side Effects:
273 **		Sets the fatal error bit in the envelope as appropriate.
274 */
275 
276 puterrmsg(msg)
277 	char *msg;
278 {
279 	/* output the message as usual */
280 	putmsg(msg, HoldErrs);
281 
282 	/* signal the error */
283 	Errors++;
284 	if (msg[0] == '5')
285 		CurEnv->e_flags |= EF_FATALERRS;
286 }
287 /*
288 **  FMTMSG -- format a message into buffer.
289 **
290 **	Parameters:
291 **		eb -- error buffer to get result.
292 **		to -- the recipient tag for this message.
293 **		num -- arpanet error number.
294 **		en -- the error number to display.
295 **		fmt -- format of string.
296 **		a, b, c, d, e -- arguments.
297 **
298 **	Returns:
299 **		none.
300 **
301 **	Side Effects:
302 **		none.
303 */
304 
305 static void
306 fmtmsg(eb, to, num, eno, fmt, ap)
307 	register char *eb;
308 	char *to;
309 	char *num;
310 	int eno;
311 	char *fmt;
312 	va_list ap;
313 {
314 	char del;
315 
316 	/* output the reply code */
317 	if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
318 	{
319 		num = fmt;
320 		fmt += 4;
321 	}
322 	if (num[3] == '-')
323 		del = '-';
324 	else
325 		del = ' ';
326 	(void) sprintf(eb, "%3.3s%c", num, del);
327 	eb += 4;
328 
329 	/* output the file name and line number */
330 	if (FileName != NULL)
331 	{
332 		(void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
333 		eb += strlen(eb);
334 	}
335 
336 	/* output the "to" person */
337 	if (to != NULL && to[0] != '\0')
338 	{
339 		(void) sprintf(eb, "%s... ", to);
340 		while (*eb != '\0')
341 			*eb++ &= 0177;
342 	}
343 
344 	/* output the message */
345 	(void) vsprintf(eb, fmt, ap);
346 	while (*eb != '\0')
347 		*eb++ &= 0177;
348 
349 	/* output the error code, if any */
350 	if (eno != 0)
351 	{
352 		extern char *errstring();
353 
354 		(void) sprintf(eb, ": %s", errstring(eno));
355 		eb += strlen(eb);
356 	}
357 }
358 /*
359 **  ERRSTRING -- return string description of error code
360 **
361 **	Parameters:
362 **		errno -- the error number to translate
363 **
364 **	Returns:
365 **		A string description of errno.
366 **
367 **	Side Effects:
368 **		none.
369 */
370 
371 char *
372 errstring(errno)
373 	int errno;
374 {
375 	extern char *sys_errlist[];
376 	extern int sys_nerr;
377 	static char buf[MAXLINE];
378 # ifdef SMTP
379 	extern char *SmtpPhase;
380 # endif /* SMTP */
381 
382 # ifdef DAEMON
383 # ifdef ETIMEDOUT
384 	/*
385 	**  Handle special network error codes.
386 	**
387 	**	These are 4.2/4.3bsd specific; they should be in daemon.c.
388 	*/
389 
390 	switch (errno)
391 	{
392 	  case ETIMEDOUT:
393 	  case ECONNRESET:
394 		(void) strcpy(buf, sys_errlist[errno]);
395 		if (SmtpPhase != NULL)
396 		{
397 			(void) strcat(buf, " during ");
398 			(void) strcat(buf, SmtpPhase);
399 		}
400 		if (CurHostName != NULL)
401 		{
402 			(void) strcat(buf, " with ");
403 			(void) strcat(buf, CurHostName);
404 		}
405 		return (buf);
406 
407 	  case EHOSTDOWN:
408 		if (CurHostName == NULL)
409 			break;
410 		(void) sprintf(buf, "Host %s is down", CurHostName);
411 		return (buf);
412 
413 	  case ECONNREFUSED:
414 		if (CurHostName == NULL)
415 			break;
416 		(void) sprintf(buf, "Connection refused by %s", CurHostName);
417 		return (buf);
418 
419 # ifdef NAMED_BIND
420 	  case HOST_NOT_FOUND + MAX_ERRNO:
421 		return ("Name server: host not found");
422 
423 	  case TRY_AGAIN + MAX_ERRNO:
424 		return ("Name server: host name lookup failure");
425 
426 	  case NO_RECOVERY + MAX_ERRNO:
427 		return ("Name server: non-recoverable error");
428 
429 	  case NO_DATA + MAX_ERRNO:
430 		return ("Name server: no data known for name");
431 # endif
432 	}
433 # endif
434 # endif
435 
436 	if (errno > 0 && errno < sys_nerr)
437 		return (sys_errlist[errno]);
438 
439 	(void) sprintf(buf, "Error %d", errno);
440 	return (buf);
441 }
442