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