Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1983 Eric P. Allman | |
78ed81a3 | 3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
15637ed4 RG |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #ifndef lint | |
78ed81a3 | 36 | static char sccsid[] = "@(#)err.c 8.2 (Berkeley) 7/11/93"; |
15637ed4 RG |
37 | #endif /* not lint */ |
38 | ||
39 | # include "sendmail.h" | |
40 | # include <errno.h> | |
41 | # include <netdb.h> | |
42 | ||
43 | /* | |
44 | ** SYSERR -- Print error message. | |
45 | ** | |
46 | ** Prints an error message via printf to the diagnostic | |
47 | ** output. If LOG is defined, it logs it also. | |
48 | ** | |
78ed81a3 | 49 | ** If the first character of the syserr message is `!' it will |
50 | ** log this as an ALERT message and exit immediately. This can | |
51 | ** leave queue files in an indeterminate state, so it should not | |
52 | ** be used lightly. | |
53 | ** | |
15637ed4 RG |
54 | ** Parameters: |
55 | ** f -- the format string | |
56 | ** a, b, c, d, e -- parameters | |
57 | ** | |
58 | ** Returns: | |
59 | ** none | |
60 | ** Through TopFrame if QuickAbort is set. | |
61 | ** | |
62 | ** Side Effects: | |
63 | ** increments Errors. | |
64 | ** sets ExitStat. | |
65 | */ | |
66 | ||
67 | # ifdef lint | |
68 | int sys_nerr; | |
69 | char *sys_errlist[]; | |
70 | # endif lint | |
71 | char MsgBuf[BUFSIZ*2]; /* text of most recent message */ | |
72 | ||
73 | static void fmtmsg(); | |
74 | ||
78ed81a3 | 75 | void |
15637ed4 | 76 | /*VARARGS1*/ |
78ed81a3 | 77 | #ifdef __STDC__ |
78 | syserr(const char *fmt, ...) | |
79 | #else | |
80 | syserr(fmt, va_alist) | |
81 | const char *fmt; | |
82 | va_dcl | |
83 | #endif | |
15637ed4 RG |
84 | { |
85 | register char *p; | |
86 | int olderrno = errno; | |
78ed81a3 | 87 | bool panic; |
88 | VA_LOCAL_DECL | |
89 | ||
90 | panic = *fmt == '!'; | |
91 | if (panic) | |
92 | fmt++; | |
15637ed4 RG |
93 | |
94 | /* format and output the error message */ | |
95 | if (olderrno == 0) | |
78ed81a3 | 96 | p = "554"; |
15637ed4 | 97 | else |
78ed81a3 | 98 | p = "451"; |
99 | VA_START(fmt); | |
100 | fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); | |
101 | VA_END; | |
15637ed4 RG |
102 | puterrmsg(MsgBuf); |
103 | ||
104 | /* determine exit status if not already set */ | |
105 | if (ExitStat == EX_OK) | |
106 | { | |
107 | if (olderrno == 0) | |
108 | ExitStat = EX_SOFTWARE; | |
109 | else | |
110 | ExitStat = EX_OSERR; | |
111 | } | |
112 | ||
113 | # ifdef LOG | |
114 | if (LogLevel > 0) | |
78ed81a3 | 115 | syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", |
15637ed4 RG |
116 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, |
117 | &MsgBuf[4]); | |
78ed81a3 | 118 | # endif /* LOG */ |
119 | if (panic) | |
120 | { | |
121 | #ifdef XLA | |
122 | xla_all_end(); | |
123 | #endif | |
124 | exit(EX_OSERR); | |
125 | } | |
15637ed4 RG |
126 | errno = 0; |
127 | if (QuickAbort) | |
128 | longjmp(TopFrame, 2); | |
129 | } | |
130 | \f/* | |
131 | ** USRERR -- Signal user error. | |
132 | ** | |
133 | ** This is much like syserr except it is for user errors. | |
134 | ** | |
135 | ** Parameters: | |
136 | ** fmt, a, b, c, d -- printf strings | |
137 | ** | |
138 | ** Returns: | |
139 | ** none | |
140 | ** Through TopFrame if QuickAbort is set. | |
141 | ** | |
142 | ** Side Effects: | |
143 | ** increments Errors. | |
144 | */ | |
145 | ||
146 | /*VARARGS1*/ | |
78ed81a3 | 147 | void |
148 | #ifdef __STDC__ | |
149 | usrerr(const char *fmt, ...) | |
150 | #else | |
151 | usrerr(fmt, va_alist) | |
152 | const char *fmt; | |
153 | va_dcl | |
154 | #endif | |
15637ed4 | 155 | { |
78ed81a3 | 156 | VA_LOCAL_DECL |
15637ed4 | 157 | extern char SuprErrs; |
15637ed4 RG |
158 | extern int errno; |
159 | ||
160 | if (SuprErrs) | |
161 | return; | |
162 | ||
78ed81a3 | 163 | VA_START(fmt); |
164 | fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); | |
165 | VA_END; | |
15637ed4 RG |
166 | puterrmsg(MsgBuf); |
167 | ||
78ed81a3 | 168 | # ifdef LOG |
169 | if (LogLevel > 3 && LogUsrErrs) | |
170 | syslog(LOG_NOTICE, "%s: %s", | |
171 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, | |
172 | &MsgBuf[4]); | |
173 | # endif /* LOG */ | |
174 | ||
15637ed4 RG |
175 | if (QuickAbort) |
176 | longjmp(TopFrame, 1); | |
177 | } | |
178 | \f/* | |
179 | ** MESSAGE -- print message (not necessarily an error) | |
180 | ** | |
181 | ** Parameters: | |
78ed81a3 | 182 | ** msg -- the message (printf fmt) -- it can begin with |
183 | ** an SMTP reply code. If not, 050 is assumed. | |
15637ed4 RG |
184 | ** a, b, c, d, e -- printf arguments |
185 | ** | |
186 | ** Returns: | |
187 | ** none | |
188 | ** | |
189 | ** Side Effects: | |
190 | ** none. | |
191 | */ | |
192 | ||
193 | /*VARARGS2*/ | |
78ed81a3 | 194 | void |
195 | #ifdef __STDC__ | |
196 | message(const char *msg, ...) | |
197 | #else | |
198 | message(msg, va_alist) | |
199 | const char *msg; | |
200 | va_dcl | |
201 | #endif | |
15637ed4 | 202 | { |
78ed81a3 | 203 | VA_LOCAL_DECL |
204 | ||
15637ed4 | 205 | errno = 0; |
78ed81a3 | 206 | VA_START(msg); |
207 | fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); | |
208 | VA_END; | |
209 | putoutmsg(MsgBuf, FALSE); | |
15637ed4 RG |
210 | } |
211 | \f/* | |
212 | ** NMESSAGE -- print message (not necessarily an error) | |
213 | ** | |
214 | ** Just like "message" except it never puts the to... tag on. | |
215 | ** | |
216 | ** Parameters: | |
217 | ** num -- the default ARPANET error number (in ascii) | |
218 | ** msg -- the message (printf fmt) -- if it begins | |
219 | ** with three digits, this number overrides num. | |
220 | ** a, b, c, d, e -- printf arguments | |
221 | ** | |
222 | ** Returns: | |
223 | ** none | |
224 | ** | |
225 | ** Side Effects: | |
226 | ** none. | |
227 | */ | |
228 | ||
229 | /*VARARGS2*/ | |
78ed81a3 | 230 | void |
231 | #ifdef __STDC__ | |
232 | nmessage(const char *msg, ...) | |
233 | #else | |
234 | nmessage(msg, va_alist) | |
235 | const char *msg; | |
236 | va_dcl | |
237 | #endif | |
15637ed4 | 238 | { |
78ed81a3 | 239 | VA_LOCAL_DECL |
240 | ||
15637ed4 | 241 | errno = 0; |
78ed81a3 | 242 | VA_START(msg); |
243 | fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); | |
244 | VA_END; | |
245 | putoutmsg(MsgBuf, FALSE); | |
15637ed4 RG |
246 | } |
247 | \f/* | |
78ed81a3 | 248 | ** PUTOUTMSG -- output error message to transcript and channel |
15637ed4 RG |
249 | ** |
250 | ** Parameters: | |
251 | ** msg -- message to output (in SMTP format). | |
252 | ** holdmsg -- if TRUE, don't output a copy of the message to | |
253 | ** our output channel. | |
254 | ** | |
255 | ** Returns: | |
256 | ** none. | |
257 | ** | |
258 | ** Side Effects: | |
259 | ** Outputs msg to the transcript. | |
260 | ** If appropriate, outputs it to the channel. | |
261 | ** Deletes SMTP reply code number as appropriate. | |
262 | */ | |
263 | ||
78ed81a3 | 264 | putoutmsg(msg, holdmsg) |
15637ed4 RG |
265 | char *msg; |
266 | bool holdmsg; | |
267 | { | |
268 | /* output to transcript if serious */ | |
269 | if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5')) | |
270 | fprintf(CurEnv->e_xfp, "%s\n", msg); | |
271 | ||
272 | /* output to channel if appropriate */ | |
78ed81a3 | 273 | if (holdmsg || (!Verbose && msg[0] == '0')) |
274 | return; | |
275 | ||
276 | (void) fflush(stdout); | |
277 | if (OpMode == MD_SMTP) | |
278 | fprintf(OutChannel, "%s\r\n", msg); | |
279 | else | |
280 | fprintf(OutChannel, "%s\n", &msg[4]); | |
281 | if (TrafficLogFile != NULL) | |
282 | fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), | |
283 | OpMode == MD_SMTP ? msg : &msg[4]); | |
284 | if (msg[3] == ' ') | |
15637ed4 | 285 | (void) fflush(OutChannel); |
78ed81a3 | 286 | if (!ferror(OutChannel)) |
287 | return; | |
288 | ||
289 | /* error on output -- if reporting lost channel, just ignore it */ | |
290 | if (feof(InChannel) || ferror(InChannel)) | |
291 | return; | |
292 | ||
293 | /* can't call syserr, 'cause we are using MsgBuf */ | |
294 | HoldErrs = TRUE; | |
295 | #ifdef LOG | |
296 | if (LogLevel > 0) | |
297 | syslog(LOG_CRIT, | |
298 | "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"", | |
299 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, | |
300 | CurHostName, msg); | |
301 | #endif | |
15637ed4 RG |
302 | } |
303 | \f/* | |
78ed81a3 | 304 | ** PUTERRMSG -- like putoutmsg, but does special processing for error messages |
15637ed4 RG |
305 | ** |
306 | ** Parameters: | |
307 | ** msg -- the message to output. | |
308 | ** | |
309 | ** Returns: | |
310 | ** none. | |
311 | ** | |
312 | ** Side Effects: | |
313 | ** Sets the fatal error bit in the envelope as appropriate. | |
314 | */ | |
315 | ||
316 | puterrmsg(msg) | |
317 | char *msg; | |
318 | { | |
319 | /* output the message as usual */ | |
78ed81a3 | 320 | putoutmsg(msg, HoldErrs); |
15637ed4 RG |
321 | |
322 | /* signal the error */ | |
323 | Errors++; | |
324 | if (msg[0] == '5') | |
325 | CurEnv->e_flags |= EF_FATALERRS; | |
326 | } | |
327 | \f/* | |
328 | ** FMTMSG -- format a message into buffer. | |
329 | ** | |
330 | ** Parameters: | |
331 | ** eb -- error buffer to get result. | |
332 | ** to -- the recipient tag for this message. | |
333 | ** num -- arpanet error number. | |
334 | ** en -- the error number to display. | |
335 | ** fmt -- format of string. | |
336 | ** a, b, c, d, e -- arguments. | |
337 | ** | |
338 | ** Returns: | |
339 | ** none. | |
340 | ** | |
341 | ** Side Effects: | |
342 | ** none. | |
343 | */ | |
344 | ||
15637ed4 | 345 | static void |
78ed81a3 | 346 | fmtmsg(eb, to, num, eno, fmt, ap) |
15637ed4 RG |
347 | register char *eb; |
348 | char *to; | |
349 | char *num; | |
350 | int eno; | |
351 | char *fmt; | |
78ed81a3 | 352 | va_list ap; |
15637ed4 RG |
353 | { |
354 | char del; | |
78ed81a3 | 355 | char *meb; |
15637ed4 RG |
356 | |
357 | /* output the reply code */ | |
358 | if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) | |
359 | { | |
360 | num = fmt; | |
361 | fmt += 4; | |
362 | } | |
363 | if (num[3] == '-') | |
364 | del = '-'; | |
365 | else | |
366 | del = ' '; | |
367 | (void) sprintf(eb, "%3.3s%c", num, del); | |
368 | eb += 4; | |
369 | ||
370 | /* output the file name and line number */ | |
371 | if (FileName != NULL) | |
372 | { | |
373 | (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); | |
374 | eb += strlen(eb); | |
375 | } | |
376 | ||
377 | /* output the "to" person */ | |
378 | if (to != NULL && to[0] != '\0') | |
379 | { | |
380 | (void) sprintf(eb, "%s... ", to); | |
381 | while (*eb != '\0') | |
382 | *eb++ &= 0177; | |
383 | } | |
384 | ||
78ed81a3 | 385 | meb = eb; |
386 | ||
15637ed4 | 387 | /* output the message */ |
78ed81a3 | 388 | (void) vsprintf(eb, fmt, ap); |
15637ed4 RG |
389 | while (*eb != '\0') |
390 | *eb++ &= 0177; | |
391 | ||
392 | /* output the error code, if any */ | |
393 | if (eno != 0) | |
394 | { | |
15637ed4 RG |
395 | (void) sprintf(eb, ": %s", errstring(eno)); |
396 | eb += strlen(eb); | |
397 | } | |
78ed81a3 | 398 | |
399 | if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL) | |
400 | CurEnv->e_message = newstr(meb); | |
15637ed4 RG |
401 | } |
402 | \f/* | |
403 | ** ERRSTRING -- return string description of error code | |
404 | ** | |
405 | ** Parameters: | |
406 | ** errno -- the error number to translate | |
407 | ** | |
408 | ** Returns: | |
409 | ** A string description of errno. | |
410 | ** | |
411 | ** Side Effects: | |
412 | ** none. | |
413 | */ | |
414 | ||
78ed81a3 | 415 | const char * |
15637ed4 RG |
416 | errstring(errno) |
417 | int errno; | |
418 | { | |
78ed81a3 | 419 | extern const char *const sys_errlist[]; |
15637ed4 | 420 | extern int sys_nerr; |
78ed81a3 | 421 | static char buf[MAXLINE]; |
15637ed4 RG |
422 | # ifdef SMTP |
423 | extern char *SmtpPhase; | |
78ed81a3 | 424 | # endif /* SMTP */ |
15637ed4 RG |
425 | |
426 | # ifdef DAEMON | |
78ed81a3 | 427 | # ifdef ETIMEDOUT |
15637ed4 RG |
428 | /* |
429 | ** Handle special network error codes. | |
430 | ** | |
431 | ** These are 4.2/4.3bsd specific; they should be in daemon.c. | |
432 | */ | |
433 | ||
434 | switch (errno) | |
435 | { | |
436 | case ETIMEDOUT: | |
437 | case ECONNRESET: | |
438 | (void) strcpy(buf, sys_errlist[errno]); | |
439 | if (SmtpPhase != NULL) | |
440 | { | |
441 | (void) strcat(buf, " during "); | |
442 | (void) strcat(buf, SmtpPhase); | |
443 | } | |
444 | if (CurHostName != NULL) | |
445 | { | |
446 | (void) strcat(buf, " with "); | |
447 | (void) strcat(buf, CurHostName); | |
448 | } | |
449 | return (buf); | |
450 | ||
451 | case EHOSTDOWN: | |
452 | if (CurHostName == NULL) | |
453 | break; | |
454 | (void) sprintf(buf, "Host %s is down", CurHostName); | |
455 | return (buf); | |
456 | ||
457 | case ECONNREFUSED: | |
458 | if (CurHostName == NULL) | |
459 | break; | |
460 | (void) sprintf(buf, "Connection refused by %s", CurHostName); | |
461 | return (buf); | |
462 | ||
78ed81a3 | 463 | # ifdef NAMED_BIND |
464 | case HOST_NOT_FOUND + MAX_ERRNO: | |
465 | return ("Name server: host not found"); | |
466 | ||
467 | case TRY_AGAIN + MAX_ERRNO: | |
468 | return ("Name server: host name lookup failure"); | |
469 | ||
470 | case NO_RECOVERY + MAX_ERRNO: | |
471 | return ("Name server: non-recoverable error"); | |
472 | ||
473 | case NO_DATA + MAX_ERRNO: | |
474 | return ("Name server: no data known for name"); | |
475 | # endif | |
15637ed4 | 476 | } |
78ed81a3 | 477 | # endif |
478 | # endif | |
15637ed4 RG |
479 | |
480 | if (errno > 0 && errno < sys_nerr) | |
481 | return (sys_errlist[errno]); | |
482 | ||
483 | (void) sprintf(buf, "Error %d", errno); | |
484 | return (buf); | |
485 | } |