Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
eb0bafab KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
9acae8cd | 10 | static char sccsid[] = "@(#)err.c 8.8 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
96faada8 | 13 | # include "sendmail.h" |
2e3062fe | 14 | # include <errno.h> |
9fd1518e | 15 | # include <netdb.h> |
b3cbe40f EA |
16 | |
17 | /* | |
d916f0ca | 18 | ** SYSERR -- Print error message. |
b3cbe40f EA |
19 | ** |
20 | ** Prints an error message via printf to the diagnostic | |
21 | ** output. If LOG is defined, it logs it also. | |
22 | ** | |
e0539260 EA |
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 | ** | |
b3cbe40f EA |
28 | ** Parameters: |
29 | ** f -- the format string | |
30 | ** a, b, c, d, e -- parameters | |
31 | ** | |
32 | ** Returns: | |
29871fef | 33 | ** none |
633a2e02 | 34 | ** Through TopFrame if QuickAbort is set. |
b3cbe40f EA |
35 | ** |
36 | ** Side Effects: | |
d916f0ca EA |
37 | ** increments Errors. |
38 | ** sets ExitStat. | |
b3cbe40f EA |
39 | */ |
40 | ||
044ab67a | 41 | char MsgBuf[BUFSIZ*2]; /* text of most recent message */ |
29871fef | 42 | |
35f1f39e EA |
43 | static void fmtmsg(); |
44 | ||
45 | #if defined(NAMED_BIND) && !defined(NO_DATA) | |
46 | # define NO_DATA NO_ADDRESS | |
47 | #endif | |
0df908a9 | 48 | |
36335805 | 49 | void |
b3cbe40f | 50 | /*VARARGS1*/ |
6e99f903 | 51 | #ifdef __STDC__ |
c51d6c4c | 52 | syserr(const char *fmt, ...) |
6e99f903 EA |
53 | #else |
54 | syserr(fmt, va_alist) | |
c51d6c4c | 55 | const char *fmt; |
6e99f903 EA |
56 | va_dcl |
57 | #endif | |
b3cbe40f | 58 | { |
177b9da3 EA |
59 | register char *p; |
60 | int olderrno = errno; | |
e0539260 | 61 | bool panic; |
5229f34d | 62 | VA_LOCAL_DECL |
b3cbe40f | 63 | |
e0539260 EA |
64 | panic = *fmt == '!'; |
65 | if (panic) | |
66 | fmt++; | |
67 | ||
d5dba2cd | 68 | /* format and output the error message */ |
177b9da3 | 69 | if (olderrno == 0) |
b6edea3d | 70 | p = "554"; |
314d2f52 | 71 | else |
b6edea3d | 72 | p = "451"; |
5229f34d EA |
73 | VA_START(fmt); |
74 | fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); | |
75 | VA_END; | |
80482eb5 | 76 | puterrmsg(MsgBuf); |
f4e91ea7 | 77 | |
b3cbe40f EA |
78 | /* determine exit status if not already set */ |
79 | if (ExitStat == EX_OK) | |
80 | { | |
177b9da3 | 81 | if (olderrno == 0) |
b3cbe40f EA |
82 | ExitStat = EX_SOFTWARE; |
83 | else | |
21ec078e | 84 | ExitStat = EX_OSERR; |
b3cbe40f EA |
85 | } |
86 | ||
87 | # ifdef LOG | |
9678c96d | 88 | if (LogLevel > 0) |
e0539260 | 89 | syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", |
3312f93c EA |
90 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, |
91 | &MsgBuf[4]); | |
f3d8f6d6 | 92 | # endif /* LOG */ |
e0539260 | 93 | if (panic) |
b4f81c5d EA |
94 | { |
95 | #ifdef XLA | |
96 | xla_all_end(); | |
97 | #endif | |
e0539260 | 98 | exit(EX_OSERR); |
b4f81c5d | 99 | } |
b3cbe40f | 100 | errno = 0; |
633a2e02 EA |
101 | if (QuickAbort) |
102 | longjmp(TopFrame, 2); | |
b3cbe40f EA |
103 | } |
104 | \f/* | |
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: | |
29871fef | 113 | ** none |
633a2e02 | 114 | ** Through TopFrame if QuickAbort is set. |
b3cbe40f EA |
115 | ** |
116 | ** Side Effects: | |
d916f0ca | 117 | ** increments Errors. |
b3cbe40f EA |
118 | */ |
119 | ||
120 | /*VARARGS1*/ | |
94bc039a | 121 | void |
36335805 | 122 | #ifdef __STDC__ |
c51d6c4c | 123 | usrerr(const char *fmt, ...) |
6e99f903 EA |
124 | #else |
125 | usrerr(fmt, va_alist) | |
c51d6c4c | 126 | const char *fmt; |
6e99f903 EA |
127 | va_dcl |
128 | #endif | |
b3cbe40f | 129 | { |
5229f34d | 130 | VA_LOCAL_DECL |
b3cbe40f | 131 | extern char SuprErrs; |
177b9da3 | 132 | extern int errno; |
b3cbe40f EA |
133 | |
134 | if (SuprErrs) | |
29871fef | 135 | return; |
f4e91ea7 | 136 | |
5229f34d | 137 | VA_START(fmt); |
75593899 | 138 | fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); |
5229f34d | 139 | VA_END; |
80482eb5 | 140 | puterrmsg(MsgBuf); |
21f25858 | 141 | |
f61c3c40 | 142 | # ifdef LOG |
68f7099c | 143 | if (LogLevel > 3 && LogUsrErrs) |
f61c3c40 EA |
144 | syslog(LOG_NOTICE, "%s: %s", |
145 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, | |
146 | &MsgBuf[4]); | |
f3d8f6d6 | 147 | # endif /* LOG */ |
f61c3c40 | 148 | |
633a2e02 EA |
149 | if (QuickAbort) |
150 | longjmp(TopFrame, 1); | |
f4e91ea7 EA |
151 | } |
152 | \f/* | |
153 | ** MESSAGE -- print message (not necessarily an error) | |
154 | ** | |
155 | ** Parameters: | |
62869b50 EA |
156 | ** msg -- the message (printf fmt) -- it can begin with |
157 | ** an SMTP reply code. If not, 050 is assumed. | |
f4e91ea7 EA |
158 | ** a, b, c, d, e -- printf arguments |
159 | ** | |
160 | ** Returns: | |
161 | ** none | |
162 | ** | |
163 | ** Side Effects: | |
164 | ** none. | |
165 | */ | |
166 | ||
29871fef | 167 | /*VARARGS2*/ |
94bc039a | 168 | void |
319b1ec0 | 169 | #ifdef __STDC__ |
c51d6c4c | 170 | message(const char *msg, ...) |
6e99f903 | 171 | #else |
b6edea3d | 172 | message(msg, va_alist) |
c51d6c4c | 173 | const char *msg; |
6e99f903 EA |
174 | va_dcl |
175 | #endif | |
f4e91ea7 | 176 | { |
5229f34d EA |
177 | VA_LOCAL_DECL |
178 | ||
49086753 | 179 | errno = 0; |
5229f34d | 180 | VA_START(msg); |
b6edea3d | 181 | fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); |
5229f34d | 182 | VA_END; |
8e5c6745 | 183 | putoutmsg(MsgBuf, FALSE); |
015bb651 EA |
184 | } |
185 | \f/* | |
21f25858 EA |
186 | ** NMESSAGE -- print message (not necessarily an error) |
187 | ** | |
188 | ** Just like "message" except it never puts the to... tag on. | |
189 | ** | |
190 | ** Parameters: | |
191 | ** num -- the default ARPANET error number (in ascii) | |
192 | ** msg -- the message (printf fmt) -- if it begins | |
2e3062fe | 193 | ** with three digits, this number overrides num. |
21f25858 EA |
194 | ** a, b, c, d, e -- printf arguments |
195 | ** | |
196 | ** Returns: | |
197 | ** none | |
198 | ** | |
199 | ** Side Effects: | |
200 | ** none. | |
201 | */ | |
202 | ||
203 | /*VARARGS2*/ | |
94bc039a | 204 | void |
319b1ec0 | 205 | #ifdef __STDC__ |
c51d6c4c | 206 | nmessage(const char *msg, ...) |
6e99f903 | 207 | #else |
b6edea3d | 208 | nmessage(msg, va_alist) |
c51d6c4c | 209 | const char *msg; |
6e99f903 EA |
210 | va_dcl |
211 | #endif | |
21f25858 | 212 | { |
5229f34d EA |
213 | VA_LOCAL_DECL |
214 | ||
21f25858 | 215 | errno = 0; |
5229f34d | 216 | VA_START(msg); |
b6edea3d | 217 | fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); |
5229f34d | 218 | VA_END; |
8e5c6745 | 219 | putoutmsg(MsgBuf, FALSE); |
21f25858 EA |
220 | } |
221 | \f/* | |
8e5c6745 | 222 | ** PUTOUTMSG -- output error message to transcript and channel |
015bb651 EA |
223 | ** |
224 | ** Parameters: | |
225 | ** msg -- message to output (in SMTP format). | |
6a766659 EA |
226 | ** holdmsg -- if TRUE, don't output a copy of the message to |
227 | ** our output channel. | |
015bb651 EA |
228 | ** |
229 | ** Returns: | |
230 | ** none. | |
231 | ** | |
232 | ** Side Effects: | |
233 | ** Outputs msg to the transcript. | |
234 | ** If appropriate, outputs it to the channel. | |
235 | ** Deletes SMTP reply code number as appropriate. | |
236 | */ | |
49086753 | 237 | |
8e5c6745 | 238 | putoutmsg(msg, holdmsg) |
015bb651 | 239 | char *msg; |
6a766659 | 240 | bool holdmsg; |
015bb651 | 241 | { |
9acae8cd EA |
242 | /* display for debugging */ |
243 | if (tTd(54, 8)) | |
244 | printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); | |
245 | ||
d7dbe85b | 246 | /* output to transcript if serious */ |
5e2168d0 | 247 | if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) |
d7dbe85b | 248 | fprintf(CurEnv->e_xfp, "%s\n", msg); |
49086753 EA |
249 | |
250 | /* output to channel if appropriate */ | |
d907841d EA |
251 | if (holdmsg || (!Verbose && msg[0] == '0')) |
252 | return; | |
253 | ||
5e2168d0 EA |
254 | /* map warnings to something SMTP can handle */ |
255 | if (msg[0] == '6') | |
256 | msg[0] = '5'; | |
257 | ||
d907841d EA |
258 | (void) fflush(stdout); |
259 | if (OpMode == MD_SMTP) | |
260 | fprintf(OutChannel, "%s\r\n", msg); | |
261 | else | |
262 | fprintf(OutChannel, "%s\n", &msg[4]); | |
8e5c6745 EA |
263 | if (TrafficLogFile != NULL) |
264 | fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), | |
265 | OpMode == MD_SMTP ? msg : &msg[4]); | |
d907841d EA |
266 | if (msg[3] == ' ') |
267 | (void) fflush(OutChannel); | |
268 | if (!ferror(OutChannel)) | |
269 | return; | |
270 | ||
271 | /* error on output -- if reporting lost channel, just ignore it */ | |
272 | if (feof(InChannel) || ferror(InChannel)) | |
273 | return; | |
274 | ||
275 | /* can't call syserr, 'cause we are using MsgBuf */ | |
276 | HoldErrs = TRUE; | |
a9145676 | 277 | #ifdef LOG |
d907841d EA |
278 | if (LogLevel > 0) |
279 | syslog(LOG_CRIT, | |
8e5c6745 | 280 | "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"", |
d907841d | 281 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, |
548e1aec EA |
282 | CurHostName == NULL ? "NO-HOST" : CurHostName, |
283 | msg); | |
a9145676 | 284 | #endif |
80482eb5 EA |
285 | } |
286 | \f/* | |
8e5c6745 | 287 | ** PUTERRMSG -- like putoutmsg, but does special processing for error messages |
80482eb5 EA |
288 | ** |
289 | ** Parameters: | |
290 | ** msg -- the message to output. | |
291 | ** | |
292 | ** Returns: | |
293 | ** none. | |
294 | ** | |
295 | ** Side Effects: | |
296 | ** Sets the fatal error bit in the envelope as appropriate. | |
297 | */ | |
21f25858 | 298 | |
80482eb5 EA |
299 | puterrmsg(msg) |
300 | char *msg; | |
301 | { | |
5e2168d0 EA |
302 | char msgcode = msg[0]; |
303 | ||
80482eb5 | 304 | /* output the message as usual */ |
8e5c6745 | 305 | putoutmsg(msg, HoldErrs); |
21f25858 | 306 | |
80482eb5 | 307 | /* signal the error */ |
5e2168d0 EA |
308 | if (msgcode == '6') |
309 | { | |
310 | /* notify the postmaster */ | |
311 | CurEnv->e_flags |= EF_PM_NOTIFY; | |
312 | } | |
313 | else | |
314 | { | |
315 | Errors++; | |
316 | if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) | |
317 | CurEnv->e_flags |= EF_FATALERRS; | |
318 | } | |
49086753 EA |
319 | } |
320 | \f/* | |
321 | ** FMTMSG -- format a message into buffer. | |
322 | ** | |
323 | ** Parameters: | |
324 | ** eb -- error buffer to get result. | |
325 | ** to -- the recipient tag for this message. | |
326 | ** num -- arpanet error number. | |
177b9da3 | 327 | ** en -- the error number to display. |
49086753 EA |
328 | ** fmt -- format of string. |
329 | ** a, b, c, d, e -- arguments. | |
330 | ** | |
331 | ** Returns: | |
332 | ** none. | |
333 | ** | |
334 | ** Side Effects: | |
335 | ** none. | |
336 | */ | |
337 | ||
0df908a9 | 338 | static void |
5229f34d | 339 | fmtmsg(eb, to, num, eno, fmt, ap) |
49086753 EA |
340 | register char *eb; |
341 | char *to; | |
342 | char *num; | |
e1e01376 | 343 | int eno; |
49086753 | 344 | char *fmt; |
5229f34d | 345 | va_list ap; |
49086753 EA |
346 | { |
347 | char del; | |
c281eee3 | 348 | char *meb; |
49086753 EA |
349 | |
350 | /* output the reply code */ | |
2e3062fe | 351 | if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) |
f4e91ea7 | 352 | { |
49086753 EA |
353 | num = fmt; |
354 | fmt += 4; | |
f4e91ea7 | 355 | } |
49086753 EA |
356 | if (num[3] == '-') |
357 | del = '-'; | |
358 | else | |
359 | del = ' '; | |
360 | (void) sprintf(eb, "%3.3s%c", num, del); | |
361 | eb += 4; | |
f4e91ea7 | 362 | |
7338e3d4 EA |
363 | /* output the file name and line number */ |
364 | if (FileName != NULL) | |
365 | { | |
366 | (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); | |
367 | eb += strlen(eb); | |
368 | } | |
369 | ||
49086753 EA |
370 | /* output the "to" person */ |
371 | if (to != NULL && to[0] != '\0') | |
34d37b7d | 372 | { |
49086753 | 373 | (void) sprintf(eb, "%s... ", to); |
6593367a EA |
374 | while (*eb != '\0') |
375 | *eb++ &= 0177; | |
49086753 EA |
376 | } |
377 | ||
c281eee3 EA |
378 | meb = eb; |
379 | ||
49086753 | 380 | /* output the message */ |
5229f34d | 381 | (void) vsprintf(eb, fmt, ap); |
6593367a EA |
382 | while (*eb != '\0') |
383 | *eb++ &= 0177; | |
34d37b7d | 384 | |
49086753 | 385 | /* output the error code, if any */ |
e1e01376 | 386 | if (eno != 0) |
49086753 | 387 | { |
e1e01376 | 388 | (void) sprintf(eb, ": %s", errstring(eno)); |
49086753 | 389 | eb += strlen(eb); |
34d37b7d | 390 | } |
c281eee3 | 391 | |
7ffb494c | 392 | if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL) |
c281eee3 | 393 | CurEnv->e_message = newstr(meb); |
b3cbe40f | 394 | } |
e41c463e EA |
395 | \f/* |
396 | ** ERRSTRING -- return string description of error code | |
397 | ** | |
398 | ** Parameters: | |
399 | ** errno -- the error number to translate | |
400 | ** | |
401 | ** Returns: | |
402 | ** A string description of errno. | |
403 | ** | |
404 | ** Side Effects: | |
405 | ** none. | |
406 | */ | |
407 | ||
713c523f | 408 | const char * |
e41c463e EA |
409 | errstring(errno) |
410 | int errno; | |
411 | { | |
f43b04ce | 412 | static char buf[MAXLINE]; |
d4f6a25e EA |
413 | # ifndef ERRLIST_PREDEFINED |
414 | extern char *sys_errlist[]; | |
415 | extern int sys_nerr; | |
416 | # endif | |
2e3062fe EA |
417 | # ifdef SMTP |
418 | extern char *SmtpPhase; | |
f3d8f6d6 | 419 | # endif /* SMTP */ |
2e3062fe EA |
420 | |
421 | # ifdef DAEMON | |
140717b5 | 422 | # ifdef ETIMEDOUT |
2e3062fe EA |
423 | /* |
424 | ** Handle special network error codes. | |
425 | ** | |
426 | ** These are 4.2/4.3bsd specific; they should be in daemon.c. | |
427 | */ | |
428 | ||
429 | switch (errno) | |
430 | { | |
431 | case ETIMEDOUT: | |
432 | case ECONNRESET: | |
433 | (void) strcpy(buf, sys_errlist[errno]); | |
434 | if (SmtpPhase != NULL) | |
435 | { | |
436 | (void) strcat(buf, " during "); | |
437 | (void) strcat(buf, SmtpPhase); | |
438 | } | |
57c97d4a | 439 | if (CurHostName != NULL) |
2e3062fe EA |
440 | { |
441 | (void) strcat(buf, " with "); | |
57c97d4a | 442 | (void) strcat(buf, CurHostName); |
2e3062fe EA |
443 | } |
444 | return (buf); | |
445 | ||
446 | case EHOSTDOWN: | |
57c97d4a | 447 | if (CurHostName == NULL) |
2e3062fe | 448 | break; |
57c97d4a | 449 | (void) sprintf(buf, "Host %s is down", CurHostName); |
2e3062fe EA |
450 | return (buf); |
451 | ||
452 | case ECONNREFUSED: | |
57c97d4a | 453 | if (CurHostName == NULL) |
2e3062fe | 454 | break; |
57c97d4a | 455 | (void) sprintf(buf, "Connection refused by %s", CurHostName); |
2e3062fe | 456 | return (buf); |
9fd1518e | 457 | |
92f2b65e EA |
458 | case EOPENTIMEOUT: |
459 | return "Timeout on file open"; | |
460 | ||
6feb509e | 461 | # ifdef NAMED_BIND |
92f2b65e | 462 | case HOST_NOT_FOUND + E_DNSBASE: |
49a282c6 EA |
463 | return ("Name server: host not found"); |
464 | ||
92f2b65e | 465 | case TRY_AGAIN + E_DNSBASE: |
49a282c6 EA |
466 | return ("Name server: host name lookup failure"); |
467 | ||
92f2b65e | 468 | case NO_RECOVERY + E_DNSBASE: |
49a282c6 EA |
469 | return ("Name server: non-recoverable error"); |
470 | ||
92f2b65e | 471 | case NO_DATA + E_DNSBASE: |
49a282c6 | 472 | return ("Name server: no data known for name"); |
6feb509e | 473 | # endif |
2e3062fe | 474 | } |
140717b5 EA |
475 | # endif |
476 | # endif | |
e41c463e EA |
477 | |
478 | if (errno > 0 && errno < sys_nerr) | |
479 | return (sys_errlist[errno]); | |
480 | ||
481 | (void) sprintf(buf, "Error %d", errno); | |
482 | return (buf); | |
483 | } |