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