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 | |
a6f189ae | 10 | static char sccsid[] = "@(#)err.c 8.17 (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 */ |
35f14050 | 93 | if (olderrno == EMFILE) |
deff97fd | 94 | { |
35f14050 | 95 | printopenfds(TRUE); |
deff97fd EA |
96 | mci_dump_all(TRUE); |
97 | } | |
e0539260 | 98 | if (panic) |
b4f81c5d EA |
99 | { |
100 | #ifdef XLA | |
101 | xla_all_end(); | |
102 | #endif | |
e0539260 | 103 | exit(EX_OSERR); |
b4f81c5d | 104 | } |
b3cbe40f | 105 | errno = 0; |
633a2e02 EA |
106 | if (QuickAbort) |
107 | longjmp(TopFrame, 2); | |
b3cbe40f EA |
108 | } |
109 | \f/* | |
110 | ** USRERR -- Signal user error. | |
111 | ** | |
112 | ** This is much like syserr except it is for user errors. | |
113 | ** | |
114 | ** Parameters: | |
115 | ** fmt, a, b, c, d -- printf strings | |
116 | ** | |
117 | ** Returns: | |
29871fef | 118 | ** none |
633a2e02 | 119 | ** Through TopFrame if QuickAbort is set. |
b3cbe40f EA |
120 | ** |
121 | ** Side Effects: | |
d916f0ca | 122 | ** increments Errors. |
b3cbe40f EA |
123 | */ |
124 | ||
125 | /*VARARGS1*/ | |
94bc039a | 126 | void |
36335805 | 127 | #ifdef __STDC__ |
c51d6c4c | 128 | usrerr(const char *fmt, ...) |
6e99f903 EA |
129 | #else |
130 | usrerr(fmt, va_alist) | |
c51d6c4c | 131 | const char *fmt; |
6e99f903 EA |
132 | va_dcl |
133 | #endif | |
b3cbe40f | 134 | { |
5229f34d | 135 | VA_LOCAL_DECL |
b3cbe40f EA |
136 | |
137 | if (SuprErrs) | |
29871fef | 138 | return; |
f4e91ea7 | 139 | |
5229f34d | 140 | VA_START(fmt); |
75593899 | 141 | fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); |
5229f34d | 142 | VA_END; |
80482eb5 | 143 | puterrmsg(MsgBuf); |
21f25858 | 144 | |
f61c3c40 | 145 | # ifdef LOG |
68f7099c | 146 | if (LogLevel > 3 && LogUsrErrs) |
f61c3c40 EA |
147 | syslog(LOG_NOTICE, "%s: %s", |
148 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, | |
149 | &MsgBuf[4]); | |
f3d8f6d6 | 150 | # endif /* LOG */ |
f61c3c40 | 151 | |
633a2e02 EA |
152 | if (QuickAbort) |
153 | longjmp(TopFrame, 1); | |
f4e91ea7 EA |
154 | } |
155 | \f/* | |
156 | ** MESSAGE -- print message (not necessarily an error) | |
157 | ** | |
158 | ** Parameters: | |
62869b50 EA |
159 | ** msg -- the message (printf fmt) -- it can begin with |
160 | ** an SMTP reply code. If not, 050 is assumed. | |
f4e91ea7 EA |
161 | ** a, b, c, d, e -- printf arguments |
162 | ** | |
163 | ** Returns: | |
164 | ** none | |
165 | ** | |
166 | ** Side Effects: | |
167 | ** none. | |
168 | */ | |
169 | ||
29871fef | 170 | /*VARARGS2*/ |
94bc039a | 171 | void |
319b1ec0 | 172 | #ifdef __STDC__ |
c51d6c4c | 173 | message(const char *msg, ...) |
6e99f903 | 174 | #else |
b6edea3d | 175 | message(msg, va_alist) |
c51d6c4c | 176 | const char *msg; |
6e99f903 EA |
177 | va_dcl |
178 | #endif | |
f4e91ea7 | 179 | { |
5229f34d EA |
180 | VA_LOCAL_DECL |
181 | ||
49086753 | 182 | errno = 0; |
5229f34d | 183 | VA_START(msg); |
b6edea3d | 184 | fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); |
5229f34d | 185 | VA_END; |
8e5c6745 | 186 | putoutmsg(MsgBuf, FALSE); |
015bb651 EA |
187 | } |
188 | \f/* | |
21f25858 EA |
189 | ** NMESSAGE -- print message (not necessarily an error) |
190 | ** | |
191 | ** Just like "message" except it never puts the to... tag on. | |
192 | ** | |
193 | ** Parameters: | |
194 | ** num -- the default ARPANET error number (in ascii) | |
195 | ** msg -- the message (printf fmt) -- if it begins | |
2e3062fe | 196 | ** with three digits, this number overrides num. |
21f25858 EA |
197 | ** a, b, c, d, e -- printf arguments |
198 | ** | |
199 | ** Returns: | |
200 | ** none | |
201 | ** | |
202 | ** Side Effects: | |
203 | ** none. | |
204 | */ | |
205 | ||
206 | /*VARARGS2*/ | |
94bc039a | 207 | void |
319b1ec0 | 208 | #ifdef __STDC__ |
c51d6c4c | 209 | nmessage(const char *msg, ...) |
6e99f903 | 210 | #else |
b6edea3d | 211 | nmessage(msg, va_alist) |
c51d6c4c | 212 | const char *msg; |
6e99f903 EA |
213 | va_dcl |
214 | #endif | |
21f25858 | 215 | { |
5229f34d EA |
216 | VA_LOCAL_DECL |
217 | ||
21f25858 | 218 | errno = 0; |
5229f34d | 219 | VA_START(msg); |
b6edea3d | 220 | fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); |
5229f34d | 221 | VA_END; |
8e5c6745 | 222 | putoutmsg(MsgBuf, FALSE); |
21f25858 EA |
223 | } |
224 | \f/* | |
8e5c6745 | 225 | ** PUTOUTMSG -- output error message to transcript and channel |
015bb651 EA |
226 | ** |
227 | ** Parameters: | |
228 | ** msg -- message to output (in SMTP format). | |
6a766659 EA |
229 | ** holdmsg -- if TRUE, don't output a copy of the message to |
230 | ** our output channel. | |
015bb651 EA |
231 | ** |
232 | ** Returns: | |
233 | ** none. | |
234 | ** | |
235 | ** Side Effects: | |
236 | ** Outputs msg to the transcript. | |
237 | ** If appropriate, outputs it to the channel. | |
238 | ** Deletes SMTP reply code number as appropriate. | |
239 | */ | |
49086753 | 240 | |
8e5c6745 | 241 | putoutmsg(msg, holdmsg) |
015bb651 | 242 | char *msg; |
6a766659 | 243 | bool holdmsg; |
015bb651 | 244 | { |
9acae8cd EA |
245 | /* display for debugging */ |
246 | if (tTd(54, 8)) | |
247 | printf("--- %s%s\n", msg, holdmsg ? " (held)" : ""); | |
248 | ||
d7dbe85b | 249 | /* output to transcript if serious */ |
5e2168d0 | 250 | if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) |
d7dbe85b | 251 | fprintf(CurEnv->e_xfp, "%s\n", msg); |
49086753 EA |
252 | |
253 | /* output to channel if appropriate */ | |
d907841d EA |
254 | if (holdmsg || (!Verbose && msg[0] == '0')) |
255 | return; | |
256 | ||
5e2168d0 EA |
257 | /* map warnings to something SMTP can handle */ |
258 | if (msg[0] == '6') | |
259 | msg[0] = '5'; | |
260 | ||
d907841d EA |
261 | (void) fflush(stdout); |
262 | if (OpMode == MD_SMTP) | |
263 | fprintf(OutChannel, "%s\r\n", msg); | |
264 | else | |
265 | fprintf(OutChannel, "%s\n", &msg[4]); | |
8e5c6745 EA |
266 | if (TrafficLogFile != NULL) |
267 | fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), | |
268 | OpMode == MD_SMTP ? msg : &msg[4]); | |
d907841d EA |
269 | if (msg[3] == ' ') |
270 | (void) fflush(OutChannel); | |
271 | if (!ferror(OutChannel)) | |
272 | return; | |
273 | ||
b3454503 EA |
274 | /* |
275 | ** Error on output -- if reporting lost channel, just ignore it. | |
276 | ** Also, ignore errors from QUIT response (221 message) -- some | |
277 | ** rude servers don't read result. | |
278 | */ | |
279 | ||
280 | if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0) | |
d907841d EA |
281 | return; |
282 | ||
283 | /* can't call syserr, 'cause we are using MsgBuf */ | |
284 | HoldErrs = TRUE; | |
a9145676 | 285 | #ifdef LOG |
d907841d EA |
286 | if (LogLevel > 0) |
287 | syslog(LOG_CRIT, | |
b3454503 | 288 | "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %m", |
d907841d | 289 | CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, |
548e1aec EA |
290 | CurHostName == NULL ? "NO-HOST" : CurHostName, |
291 | msg); | |
a9145676 | 292 | #endif |
80482eb5 EA |
293 | } |
294 | \f/* | |
8e5c6745 | 295 | ** PUTERRMSG -- like putoutmsg, but does special processing for error messages |
80482eb5 EA |
296 | ** |
297 | ** Parameters: | |
298 | ** msg -- the message to output. | |
299 | ** | |
300 | ** Returns: | |
301 | ** none. | |
302 | ** | |
303 | ** Side Effects: | |
304 | ** Sets the fatal error bit in the envelope as appropriate. | |
305 | */ | |
21f25858 | 306 | |
80482eb5 EA |
307 | puterrmsg(msg) |
308 | char *msg; | |
309 | { | |
5e2168d0 EA |
310 | char msgcode = msg[0]; |
311 | ||
80482eb5 | 312 | /* output the message as usual */ |
8e5c6745 | 313 | putoutmsg(msg, HoldErrs); |
21f25858 | 314 | |
80482eb5 | 315 | /* signal the error */ |
e67e6cf6 | 316 | Errors++; |
2aad48ef EA |
317 | if (msgcode == '6') |
318 | { | |
319 | /* notify the postmaster */ | |
320 | CurEnv->e_flags |= EF_PM_NOTIFY; | |
321 | } | |
e67e6cf6 EA |
322 | else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) |
323 | { | |
324 | /* mark long-term fatal errors */ | |
325 | CurEnv->e_flags |= EF_FATALERRS; | |
326 | } | |
49086753 EA |
327 | } |
328 | \f/* | |
329 | ** FMTMSG -- format a message into buffer. | |
330 | ** | |
331 | ** Parameters: | |
332 | ** eb -- error buffer to get result. | |
333 | ** to -- the recipient tag for this message. | |
334 | ** num -- arpanet error number. | |
177b9da3 | 335 | ** en -- the error number to display. |
49086753 EA |
336 | ** fmt -- format of string. |
337 | ** a, b, c, d, e -- arguments. | |
338 | ** | |
339 | ** Returns: | |
340 | ** none. | |
341 | ** | |
342 | ** Side Effects: | |
343 | ** none. | |
344 | */ | |
345 | ||
0df908a9 | 346 | static void |
5229f34d | 347 | fmtmsg(eb, to, num, eno, fmt, ap) |
49086753 EA |
348 | register char *eb; |
349 | char *to; | |
350 | char *num; | |
e1e01376 | 351 | int eno; |
49086753 | 352 | char *fmt; |
5229f34d | 353 | va_list ap; |
49086753 EA |
354 | { |
355 | char del; | |
c281eee3 | 356 | char *meb; |
49086753 EA |
357 | |
358 | /* output the reply code */ | |
2e3062fe | 359 | if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) |
f4e91ea7 | 360 | { |
49086753 EA |
361 | num = fmt; |
362 | fmt += 4; | |
f4e91ea7 | 363 | } |
49086753 EA |
364 | if (num[3] == '-') |
365 | del = '-'; | |
366 | else | |
367 | del = ' '; | |
368 | (void) sprintf(eb, "%3.3s%c", num, del); | |
369 | eb += 4; | |
f4e91ea7 | 370 | |
7338e3d4 EA |
371 | /* output the file name and line number */ |
372 | if (FileName != NULL) | |
373 | { | |
374 | (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); | |
375 | eb += strlen(eb); | |
376 | } | |
377 | ||
49086753 EA |
378 | /* output the "to" person */ |
379 | if (to != NULL && to[0] != '\0') | |
34d37b7d | 380 | { |
49086753 | 381 | (void) sprintf(eb, "%s... ", to); |
6593367a EA |
382 | while (*eb != '\0') |
383 | *eb++ &= 0177; | |
49086753 EA |
384 | } |
385 | ||
c281eee3 EA |
386 | meb = eb; |
387 | ||
49086753 | 388 | /* output the message */ |
5229f34d | 389 | (void) vsprintf(eb, fmt, ap); |
6593367a EA |
390 | while (*eb != '\0') |
391 | *eb++ &= 0177; | |
34d37b7d | 392 | |
49086753 | 393 | /* output the error code, if any */ |
e1e01376 | 394 | if (eno != 0) |
49086753 | 395 | { |
e1e01376 | 396 | (void) sprintf(eb, ": %s", errstring(eno)); |
49086753 | 397 | eb += strlen(eb); |
34d37b7d | 398 | } |
c281eee3 | 399 | |
f6a83527 EA |
400 | if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4')) |
401 | { | |
402 | if (CurEnv->e_message != NULL) | |
403 | free(CurEnv->e_message); | |
c281eee3 | 404 | CurEnv->e_message = newstr(meb); |
f6a83527 | 405 | } |
b3cbe40f | 406 | } |
e41c463e EA |
407 | \f/* |
408 | ** ERRSTRING -- return string description of error code | |
409 | ** | |
410 | ** Parameters: | |
411 | ** errno -- the error number to translate | |
412 | ** | |
413 | ** Returns: | |
414 | ** A string description of errno. | |
415 | ** | |
416 | ** Side Effects: | |
417 | ** none. | |
418 | */ | |
419 | ||
713c523f | 420 | const char * |
e41c463e EA |
421 | errstring(errno) |
422 | int errno; | |
423 | { | |
f43b04ce | 424 | static char buf[MAXLINE]; |
d4f6a25e EA |
425 | # ifndef ERRLIST_PREDEFINED |
426 | extern char *sys_errlist[]; | |
427 | extern int sys_nerr; | |
428 | # endif | |
2e3062fe EA |
429 | # ifdef SMTP |
430 | extern char *SmtpPhase; | |
f3d8f6d6 | 431 | # endif /* SMTP */ |
2e3062fe | 432 | |
2e3062fe EA |
433 | /* |
434 | ** Handle special network error codes. | |
435 | ** | |
436 | ** These are 4.2/4.3bsd specific; they should be in daemon.c. | |
437 | */ | |
438 | ||
439 | switch (errno) | |
440 | { | |
7763037f | 441 | # if defined(DAEMON) && defined(ETIMEDOUT) |
2e3062fe EA |
442 | case ETIMEDOUT: |
443 | case ECONNRESET: | |
444 | (void) strcpy(buf, sys_errlist[errno]); | |
445 | if (SmtpPhase != NULL) | |
446 | { | |
447 | (void) strcat(buf, " during "); | |
448 | (void) strcat(buf, SmtpPhase); | |
449 | } | |
57c97d4a | 450 | if (CurHostName != NULL) |
2e3062fe EA |
451 | { |
452 | (void) strcat(buf, " with "); | |
57c97d4a | 453 | (void) strcat(buf, CurHostName); |
2e3062fe EA |
454 | } |
455 | return (buf); | |
456 | ||
457 | case EHOSTDOWN: | |
57c97d4a | 458 | if (CurHostName == NULL) |
2e3062fe | 459 | break; |
57c97d4a | 460 | (void) sprintf(buf, "Host %s is down", CurHostName); |
2e3062fe EA |
461 | return (buf); |
462 | ||
463 | case ECONNREFUSED: | |
57c97d4a | 464 | if (CurHostName == NULL) |
2e3062fe | 465 | break; |
57c97d4a | 466 | (void) sprintf(buf, "Connection refused by %s", CurHostName); |
2e3062fe | 467 | return (buf); |
7763037f | 468 | # endif |
9fd1518e | 469 | |
92f2b65e EA |
470 | case EOPENTIMEOUT: |
471 | return "Timeout on file open"; | |
472 | ||
6feb509e | 473 | # ifdef NAMED_BIND |
92f2b65e | 474 | case HOST_NOT_FOUND + E_DNSBASE: |
a6f189ae | 475 | return ("Name server: %s: host not found", CurHostName); |
49a282c6 | 476 | |
92f2b65e | 477 | case TRY_AGAIN + E_DNSBASE: |
a6f189ae | 478 | return ("Name server: %s: host name lookup failure", CurHostName); |
49a282c6 | 479 | |
92f2b65e | 480 | case NO_RECOVERY + E_DNSBASE: |
a6f189ae | 481 | return ("Name server: %s: non-recoverable error", CurHostName); |
49a282c6 | 482 | |
92f2b65e | 483 | case NO_DATA + E_DNSBASE: |
a6f189ae | 484 | return ("Name server: %s: no data known", CurHostName); |
6feb509e | 485 | # endif |
7763037f EA |
486 | |
487 | case EPERM: | |
488 | /* SunOS gives "Not owner" -- this is the POSIX message */ | |
489 | return "Operation not permitted"; | |
2e3062fe | 490 | } |
e41c463e EA |
491 | |
492 | if (errno > 0 && errno < sys_nerr) | |
493 | return (sys_errlist[errno]); | |
494 | ||
495 | (void) sprintf(buf, "Error %d", errno); | |
496 | return (buf); | |
497 | } |