Remove tm.h and xm.h handling, as it wasn't used. Use nm.h only when needed.
[dragonfly.git] / contrib / sendmail-8.14 / sendmail / err.c
blob5825666e62345071ad371f51aad3983607040ba8
1 /*
2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
14 #include <sendmail.h>
16 SM_RCSID("@(#)$Id: err.c,v 8.196 2006/11/10 23:14:08 ca Exp $")
18 #if LDAPMAP
19 # include <lber.h>
20 # include <ldap.h> /* for LDAP error codes */
21 #endif /* LDAPMAP */
23 static void putoutmsg __P((char *, bool, bool));
24 static void puterrmsg __P((char *));
25 static char *fmtmsg __P((char *, const char *, const char *, const char *,
26 int, const char *, va_list));
29 ** FATAL_ERROR -- handle a fatal exception
31 ** This function is installed as the default exception handler
32 ** in the main sendmail process, and in all child processes
33 ** that we create. Its job is to handle exceptions that are not
34 ** handled at a lower level.
36 ** The theory is that unhandled exceptions will be 'fatal' class
37 ** exceptions (with an "F:" prefix), such as the out-of-memory
38 ** exception "F:sm.heap". As such, they are handled by exiting
39 ** the process in exactly the same way that xalloc() in Sendmail 8.10
40 ** exits the process when it fails due to lack of memory:
41 ** we call syserr with a message beginning with "!".
43 ** Parameters:
44 ** exc -- exception which is terminating this process
46 ** Returns:
47 ** none
50 void
51 fatal_error(exc)
52 SM_EXC_T *exc;
54 static char buf[256];
55 SM_FILE_T f;
58 ** This function may be called when the heap is exhausted.
59 ** The following code writes the message for 'exc' into our
60 ** static buffer without allocating memory or raising exceptions.
63 sm_strio_init(&f, buf, sizeof(buf));
64 sm_exc_write(exc, &f);
65 (void) sm_io_flush(&f, SM_TIME_DEFAULT);
68 ** Terminate the process after logging an error and cleaning up.
69 ** Problems:
70 ** - syserr decides what class of error this is by looking at errno.
71 ** That's no good; we should look at the exc structure.
72 ** - The cleanup code should be moved out of syserr
73 ** and into individual exception handlers
74 ** that are part of the module they clean up after.
77 errno = ENOMEM;
78 syserr("!%s", buf);
82 ** SYSERR -- Print error message.
84 ** Prints an error message via sm_io_printf to the diagnostic output.
86 ** If the first character of the syserr message is `!' it will
87 ** log this as an ALERT message and exit immediately. This can
88 ** leave queue files in an indeterminate state, so it should not
89 ** be used lightly.
91 ** If the first character of the syserr message is '!' or '@'
92 ** then syserr knows that the process is about to be terminated,
93 ** so the SMTP reply code defaults to 421. Otherwise, the
94 ** reply code defaults to 451 or 554, depending on errno.
96 ** Parameters:
97 ** fmt -- the format string. An optional '!' or '@',
98 ** followed by an optional three-digit SMTP
99 ** reply code, followed by message text.
100 ** (others) -- parameters
102 ** Returns:
103 ** none
104 ** Raises E:mta.quickabort if QuickAbort is set.
106 ** Side Effects:
107 ** increments Errors.
108 ** sets ExitStat.
111 char MsgBuf[BUFSIZ*2]; /* text of most recent message */
112 static char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */
114 #if NAMED_BIND && !defined(NO_DATA)
115 # define NO_DATA NO_ADDRESS
116 #endif /* NAMED_BIND && !defined(NO_DATA) */
118 void
119 /*VARARGS1*/
120 #ifdef __STDC__
121 syserr(const char *fmt, ...)
122 #else /* __STDC__ */
123 syserr(fmt, va_alist)
124 const char *fmt;
125 va_dcl
126 #endif /* __STDC__ */
128 register char *p;
129 int save_errno = errno;
130 bool panic;
131 bool exiting;
132 char *user;
133 char *enhsc;
134 char *errtxt;
135 struct passwd *pw;
136 char ubuf[80];
137 SM_VA_LOCAL_DECL
139 switch (*fmt)
141 case '!':
142 ++fmt;
143 panic = true;
144 exiting = true;
145 break;
146 case '@':
147 ++fmt;
148 panic = false;
149 exiting = true;
150 break;
151 default:
152 panic = false;
153 exiting = false;
154 break;
157 /* format and output the error message */
158 if (exiting)
161 ** Since we are terminating the process,
162 ** we are aborting the entire SMTP session,
163 ** rather than just the current transaction.
166 p = "421";
167 enhsc = "4.0.0";
169 else if (save_errno == 0)
171 p = "554";
172 enhsc = "5.0.0";
174 else
176 p = "451";
177 enhsc = "4.0.0";
179 SM_VA_START(ap, fmt);
180 errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
181 SM_VA_END(ap);
182 puterrmsg(MsgBuf);
184 /* save this message for mailq printing */
185 if (!panic && CurEnv != NULL)
187 char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
189 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
190 sm_free(CurEnv->e_message);
191 CurEnv->e_message = nmsg;
194 /* determine exit status if not already set */
195 if (ExitStat == EX_OK)
197 if (save_errno == 0)
198 ExitStat = EX_SOFTWARE;
199 else
200 ExitStat = EX_OSERR;
201 if (tTd(54, 1))
202 sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
205 pw = sm_getpwuid(RealUid);
206 if (pw != NULL)
207 user = pw->pw_name;
208 else
210 user = ubuf;
211 (void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid);
214 if (LogLevel > 0)
215 sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
216 CurEnv == NULL ? NOQID : CurEnv->e_id,
217 "SYSERR(%s): %.900s",
218 user, errtxt);
219 switch (save_errno)
221 case EBADF:
222 case ENFILE:
223 case EMFILE:
224 case ENOTTY:
225 #ifdef EFBIG
226 case EFBIG:
227 #endif /* EFBIG */
228 #ifdef ESPIPE
229 case ESPIPE:
230 #endif /* ESPIPE */
231 #ifdef EPIPE
232 case EPIPE:
233 #endif /* EPIPE */
234 #ifdef ENOBUFS
235 case ENOBUFS:
236 #endif /* ENOBUFS */
237 #ifdef ESTALE
238 case ESTALE:
239 #endif /* ESTALE */
240 printopenfds(true);
241 mci_dump_all(smioout, true);
242 break;
244 if (panic)
246 #if XLA
247 xla_all_end();
248 #endif /* XLA */
249 sync_queue_time();
250 if (tTd(0, 1))
251 abort();
252 exit(EX_OSERR);
254 errno = 0;
255 if (QuickAbort)
256 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
259 ** USRERR -- Signal user error.
261 ** This is much like syserr except it is for user errors.
263 ** Parameters:
264 ** fmt -- the format string. If it does not begin with
265 ** a three-digit SMTP reply code, 550 is assumed.
266 ** (others) -- sm_io_printf strings
268 ** Returns:
269 ** none
270 ** Raises E:mta.quickabort if QuickAbort is set.
272 ** Side Effects:
273 ** increments Errors.
276 /*VARARGS1*/
277 void
278 #ifdef __STDC__
279 usrerr(const char *fmt, ...)
280 #else /* __STDC__ */
281 usrerr(fmt, va_alist)
282 const char *fmt;
283 va_dcl
284 #endif /* __STDC__ */
286 char *enhsc;
287 char *errtxt;
288 SM_VA_LOCAL_DECL
290 if (fmt[0] == '5' || fmt[0] == '6')
291 enhsc = "5.0.0";
292 else if (fmt[0] == '4' || fmt[0] == '8')
293 enhsc = "4.0.0";
294 else if (fmt[0] == '2')
295 enhsc = "2.0.0";
296 else
297 enhsc = NULL;
298 SM_VA_START(ap, fmt);
299 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
300 SM_VA_END(ap);
302 if (SuprErrs)
303 return;
305 /* save this message for mailq printing */
306 switch (MsgBuf[0])
308 case '4':
309 case '8':
310 if (CurEnv->e_message != NULL)
311 break;
313 /* FALLTHROUGH */
315 case '5':
316 case '6':
317 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
318 sm_free(CurEnv->e_message);
319 if (MsgBuf[0] == '6')
321 char buf[MAXLINE];
323 (void) sm_snprintf(buf, sizeof(buf),
324 "Postmaster warning: %.*s",
325 (int) sizeof(buf) - 22, errtxt);
326 CurEnv->e_message =
327 sm_rpool_strdup_x(CurEnv->e_rpool, buf);
329 else
331 CurEnv->e_message =
332 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
334 break;
337 puterrmsg(MsgBuf);
338 if (LogLevel > 3 && LogUsrErrs)
339 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
340 if (QuickAbort)
341 sm_exc_raisenew_x(&EtypeQuickAbort, 1);
344 ** USRERRENH -- Signal user error.
346 ** Same as usrerr but with enhanced status code.
348 ** Parameters:
349 ** enhsc -- the enhanced status code.
350 ** fmt -- the format string. If it does not begin with
351 ** a three-digit SMTP reply code, 550 is assumed.
352 ** (others) -- sm_io_printf strings
354 ** Returns:
355 ** none
356 ** Raises E:mta.quickabort if QuickAbort is set.
358 ** Side Effects:
359 ** increments Errors.
362 /*VARARGS1*/
363 void
364 #ifdef __STDC__
365 usrerrenh(char *enhsc, const char *fmt, ...)
366 #else /* __STDC__ */
367 usrerrenh(enhsc, fmt, va_alist)
368 char *enhsc;
369 const char *fmt;
370 va_dcl
371 #endif /* __STDC__ */
373 char *errtxt;
374 SM_VA_LOCAL_DECL
376 if (enhsc == NULL || *enhsc == '\0')
378 if (fmt[0] == '5' || fmt[0] == '6')
379 enhsc = "5.0.0";
380 else if (fmt[0] == '4' || fmt[0] == '8')
381 enhsc = "4.0.0";
382 else if (fmt[0] == '2')
383 enhsc = "2.0.0";
385 SM_VA_START(ap, fmt);
386 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
387 SM_VA_END(ap);
389 if (SuprErrs)
390 return;
392 /* save this message for mailq printing */
393 switch (MsgBuf[0])
395 case '4':
396 case '8':
397 if (CurEnv->e_message != NULL)
398 break;
400 /* FALLTHROUGH */
402 case '5':
403 case '6':
404 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
405 sm_free(CurEnv->e_message);
406 if (MsgBuf[0] == '6')
408 char buf[MAXLINE];
410 (void) sm_snprintf(buf, sizeof(buf),
411 "Postmaster warning: %.*s",
412 (int) sizeof(buf) - 22, errtxt);
413 CurEnv->e_message =
414 sm_rpool_strdup_x(CurEnv->e_rpool, buf);
416 else
418 CurEnv->e_message =
419 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
421 break;
424 puterrmsg(MsgBuf);
425 if (LogLevel > 3 && LogUsrErrs)
426 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
427 if (QuickAbort)
428 sm_exc_raisenew_x(&EtypeQuickAbort, 1);
431 ** MESSAGE -- print message (not necessarily an error)
433 ** Parameters:
434 ** msg -- the message (sm_io_printf fmt) -- it can begin with
435 ** an SMTP reply code. If not, 050 is assumed.
436 ** (others) -- sm_io_printf arguments
438 ** Returns:
439 ** none
441 ** Side Effects:
442 ** none.
445 /*VARARGS1*/
446 void
447 #ifdef __STDC__
448 message(const char *msg, ...)
449 #else /* __STDC__ */
450 message(msg, va_alist)
451 const char *msg;
452 va_dcl
453 #endif /* __STDC__ */
455 char *errtxt;
456 SM_VA_LOCAL_DECL
458 errno = 0;
459 SM_VA_START(ap, msg);
460 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
461 SM_VA_END(ap);
462 putoutmsg(MsgBuf, false, false);
464 /* save this message for mailq printing */
465 switch (MsgBuf[0])
467 case '4':
468 case '8':
469 if (CurEnv->e_message != NULL)
470 break;
471 /* FALLTHROUGH */
473 case '5':
474 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
475 sm_free(CurEnv->e_message);
476 CurEnv->e_message =
477 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
478 break;
482 ** NMESSAGE -- print message (not necessarily an error)
484 ** Just like "message" except it never puts the to... tag on.
486 ** Parameters:
487 ** msg -- the message (sm_io_printf fmt) -- if it begins
488 ** with a three digit SMTP reply code, that is used,
489 ** otherwise 050 is assumed.
490 ** (others) -- sm_io_printf arguments
492 ** Returns:
493 ** none
495 ** Side Effects:
496 ** none.
499 /*VARARGS1*/
500 void
501 #ifdef __STDC__
502 nmessage(const char *msg, ...)
503 #else /* __STDC__ */
504 nmessage(msg, va_alist)
505 const char *msg;
506 va_dcl
507 #endif /* __STDC__ */
509 char *errtxt;
510 SM_VA_LOCAL_DECL
512 errno = 0;
513 SM_VA_START(ap, msg);
514 errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
515 (char *) NULL, 0, msg, ap);
516 SM_VA_END(ap);
517 putoutmsg(MsgBuf, false, false);
519 /* save this message for mailq printing */
520 switch (MsgBuf[0])
522 case '4':
523 case '8':
524 if (CurEnv->e_message != NULL)
525 break;
526 /* FALLTHROUGH */
528 case '5':
529 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
530 sm_free(CurEnv->e_message);
531 CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
532 break;
536 ** PUTOUTMSG -- output error message to transcript and channel
538 ** Parameters:
539 ** msg -- message to output (in SMTP format).
540 ** holdmsg -- if true, don't output a copy of the message to
541 ** our output channel.
542 ** heldmsg -- if true, this is a previously held message;
543 ** don't log it to the transcript file.
545 ** Returns:
546 ** none.
548 ** Side Effects:
549 ** Outputs msg to the transcript.
550 ** If appropriate, outputs it to the channel.
551 ** Deletes SMTP reply code number as appropriate.
554 static void
555 putoutmsg(msg, holdmsg, heldmsg)
556 char *msg;
557 bool holdmsg;
558 bool heldmsg;
560 char msgcode = msg[0];
561 char *errtxt = msg;
562 char *id;
564 /* display for debugging */
565 if (tTd(54, 8))
566 sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
567 heldmsg ? " (held)" : "");
569 /* map warnings to something SMTP can handle */
570 if (msgcode == '6')
571 msg[0] = '5';
572 else if (msgcode == '8')
573 msg[0] = '4';
574 id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
576 /* output to transcript if serious */
577 if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
578 strchr("45", msg[0]) != NULL)
579 (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
580 msg);
582 if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
583 sm_syslog(LOG_INFO, id,
584 "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
585 heldmsg ? " (held)" : "");
587 if (msgcode == '8')
588 msg[0] = '0';
590 /* output to channel if appropriate */
591 if (!Verbose && msg[0] == '0')
592 return;
593 if (holdmsg)
595 /* save for possible future display */
596 msg[0] = msgcode;
597 if (HeldMessageBuf[0] == '5' && msgcode == '4')
598 return;
599 (void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
600 return;
603 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
605 if (OutChannel == NULL)
606 return;
608 /* find actual text of error (after SMTP status codes) */
609 if (ISSMTPREPLY(errtxt))
611 int l;
613 errtxt += 4;
614 l = isenhsc(errtxt, ' ');
615 if (l <= 0)
616 l = isenhsc(errtxt, '\0');
617 if (l > 0)
618 errtxt += l + 1;
621 /* if DisConnected, OutChannel now points to the transcript */
622 if (!DisConnected &&
623 (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
624 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
625 msg);
626 else
627 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
628 errtxt);
629 if (TrafficLogFile != NULL)
630 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
631 "%05d >>> %s\n", (int) CurrentPid,
632 (OpMode == MD_SMTP || OpMode == MD_DAEMON)
633 ? msg : errtxt);
634 #if !PIPELINING
635 /* XXX can't flush here for SMTP pipelining */
636 if (msg[3] == ' ')
637 (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
638 if (!sm_io_error(OutChannel) || DisConnected)
639 return;
642 ** Error on output -- if reporting lost channel, just ignore it.
643 ** Also, ignore errors from QUIT response (221 message) -- some
644 ** rude servers don't read result.
647 if (InChannel == NULL || sm_io_eof(InChannel) ||
648 sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
649 return;
651 /* can't call syserr, 'cause we are using MsgBuf */
652 HoldErrs = true;
653 if (LogLevel > 0)
654 sm_syslog(LOG_CRIT, id,
655 "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
656 CURHOSTNAME,
657 shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
658 #endif /* !PIPELINING */
661 ** PUTERRMSG -- like putoutmsg, but does special processing for error messages
663 ** Parameters:
664 ** msg -- the message to output.
666 ** Returns:
667 ** none.
669 ** Side Effects:
670 ** Sets the fatal error bit in the envelope as appropriate.
673 static void
674 puterrmsg(msg)
675 char *msg;
677 char msgcode = msg[0];
679 /* output the message as usual */
680 putoutmsg(msg, HoldErrs, false);
682 /* be careful about multiple error messages */
683 if (OnlyOneError)
684 HoldErrs = true;
686 /* signal the error */
687 Errors++;
689 if (CurEnv == NULL)
690 return;
692 if (msgcode == '6')
694 /* notify the postmaster */
695 CurEnv->e_flags |= EF_PM_NOTIFY;
697 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
699 /* mark long-term fatal errors */
700 CurEnv->e_flags |= EF_FATALERRS;
704 ** ISENHSC -- check whether a string contains an enhanced status code
706 ** Parameters:
707 ** s -- string with possible enhanced status code.
708 ** delim -- delim for enhanced status code.
710 ** Returns:
711 ** 0 -- no enhanced status code.
712 ** >4 -- length of enhanced status code.
714 ** Side Effects:
715 ** none.
718 isenhsc(s, delim)
719 const char *s;
720 int delim;
722 int l, h;
724 if (s == NULL)
725 return 0;
726 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
727 return 0;
728 h = 0;
729 l = 2;
730 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
731 ++h;
732 if (h == 0 || s[l + h] != '.')
733 return 0;
734 l += h + 1;
735 h = 0;
736 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
737 ++h;
738 if (h == 0 || s[l + h] != delim)
739 return 0;
740 return l + h;
743 ** EXTENHSC -- check and extract an enhanced status code
745 ** Parameters:
746 ** s -- string with possible enhanced status code.
747 ** delim -- delim for enhanced status code.
748 ** e -- pointer to storage for enhanced status code.
749 ** must be != NULL and have space for at least
750 ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
752 ** Returns:
753 ** 0 -- no enhanced status code.
754 ** >4 -- length of enhanced status code.
756 ** Side Effects:
757 ** fills e with enhanced status code.
761 extenhsc(s, delim, e)
762 const char *s;
763 int delim;
764 char *e;
766 int l, h;
768 if (s == NULL)
769 return 0;
770 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
771 return 0;
772 h = 0;
773 l = 2;
774 e[0] = s[0];
775 e[1] = '.';
776 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
778 e[l + h] = s[l + h];
779 ++h;
781 if (h == 0 || s[l + h] != '.')
782 return 0;
783 e[l + h] = '.';
784 l += h + 1;
785 h = 0;
786 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
788 e[l + h] = s[l + h];
789 ++h;
791 if (h == 0 || s[l + h] != delim)
792 return 0;
793 e[l + h] = '\0';
794 return l + h;
797 ** FMTMSG -- format a message into buffer.
799 ** Parameters:
800 ** eb -- error buffer to get result -- MUST BE MsgBuf.
801 ** to -- the recipient tag for this message.
802 ** num -- default three digit SMTP reply code.
803 ** enhsc -- enhanced status code.
804 ** en -- the error number to display.
805 ** fmt -- format of string.
806 ** ap -- arguments for fmt.
808 ** Returns:
809 ** pointer to error text beyond status codes.
811 ** Side Effects:
812 ** none.
815 static char *
816 fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
817 register char *eb;
818 const char *to;
819 const char *num;
820 const char *enhsc;
821 int eno;
822 const char *fmt;
823 SM_VA_LOCAL_DECL
825 char del;
826 int l;
827 int spaceleft = sizeof(MsgBuf);
828 char *errtxt;
830 /* output the reply code */
831 if (ISSMTPCODE(fmt))
833 num = fmt;
834 fmt += 4;
836 if (num[3] == '-')
837 del = '-';
838 else
839 del = ' ';
840 if (SoftBounce && num[0] == '5')
842 /* replace 5 by 4 */
843 (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
845 else
846 (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
847 eb += 4;
848 spaceleft -= 4;
850 if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
852 /* copy enh.status code including trailing blank */
853 l++;
854 (void) sm_strlcpy(eb, fmt, l + 1);
855 eb += l;
856 spaceleft -= l;
857 fmt += l;
859 else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
861 /* copy enh.status code */
862 (void) sm_strlcpy(eb, enhsc, l + 1);
863 eb[l] = ' ';
864 eb[++l] = '\0';
865 eb += l;
866 spaceleft -= l;
868 if (SoftBounce && eb[-l] == '5')
870 /* replace 5 by 4 */
871 eb[-l] = '4';
873 errtxt = eb;
875 /* output the file name and line number */
876 if (FileName != NULL)
878 (void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
879 shortenstring(FileName, 83), LineNumber);
880 eb += (l = strlen(eb));
881 spaceleft -= l;
885 ** output the "to" address only if it is defined and one of the
886 ** following codes is used:
887 ** 050 internal notices, e.g., alias expansion
888 ** 250 Ok
889 ** 252 Cannot VRFY user, but will accept message and attempt delivery
890 ** 450 Requested mail action not taken: mailbox unavailable
891 ** 550 Requested action not taken: mailbox unavailable
892 ** 553 Requested action not taken: mailbox name not allowed
894 ** Notice: this still isn't "the right thing", this code shouldn't
895 ** (indirectly) depend on CurEnv->e_to.
898 if (to != NULL && to[0] != '\0' &&
899 (strncmp(num, "050", 3) == 0 ||
900 strncmp(num, "250", 3) == 0 ||
901 strncmp(num, "252", 3) == 0 ||
902 strncmp(num, "450", 3) == 0 ||
903 strncmp(num, "550", 3) == 0 ||
904 strncmp(num, "553", 3) == 0))
906 (void) sm_strlcpyn(eb, spaceleft, 2,
907 shortenstring(to, MAXSHORTSTR), "... ");
908 spaceleft -= strlen(eb);
909 while (*eb != '\0')
910 *eb++ &= 0177;
913 /* output the message */
914 (void) sm_vsnprintf(eb, spaceleft, fmt, ap);
915 spaceleft -= strlen(eb);
916 while (*eb != '\0')
917 *eb++ &= 0177;
919 /* output the error code, if any */
920 if (eno != 0)
921 (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
923 return errtxt;
926 ** BUFFER_ERRORS -- arrange to buffer future error messages
928 ** Parameters:
929 ** none
931 ** Returns:
932 ** none.
935 void
936 buffer_errors()
938 HeldMessageBuf[0] = '\0';
939 HoldErrs = true;
942 ** FLUSH_ERRORS -- flush the held error message buffer
944 ** Parameters:
945 ** print -- if set, print the message, otherwise just
946 ** delete it.
948 ** Returns:
949 ** none.
952 void
953 flush_errors(print)
954 bool print;
956 if (print && HeldMessageBuf[0] != '\0')
957 putoutmsg(HeldMessageBuf, false, true);
958 HeldMessageBuf[0] = '\0';
959 HoldErrs = false;
962 ** SM_ERRSTRING -- return string description of error code
964 ** Parameters:
965 ** errnum -- the error number to translate
967 ** Returns:
968 ** A string description of errnum.
970 ** Side Effects:
971 ** none.
974 const char *
975 sm_errstring(errnum)
976 int errnum;
978 char *dnsmsg;
979 char *bp;
980 static char buf[MAXLINE];
981 #if HASSTRERROR
982 char *err;
983 char errbuf[30];
984 #endif /* HASSTRERROR */
985 #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
986 extern char *sys_errlist[];
987 extern int sys_nerr;
988 #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
991 ** Handle special network error codes.
993 ** These are 4.2/4.3bsd specific; they should be in daemon.c.
996 dnsmsg = NULL;
997 switch (errnum)
999 case ETIMEDOUT:
1000 case ECONNRESET:
1001 bp = buf;
1002 #if HASSTRERROR
1003 err = strerror(errnum);
1004 if (err == NULL)
1006 (void) sm_snprintf(errbuf, sizeof(errbuf),
1007 "Error %d", errnum);
1008 err = errbuf;
1010 (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
1011 #else /* HASSTRERROR */
1012 if (errnum >= 0 && errnum < sys_nerr)
1013 (void) sm_strlcpy(bp, sys_errlist[errnum],
1014 SPACELEFT(buf, bp));
1015 else
1016 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1017 "Error %d", errnum);
1018 #endif /* HASSTRERROR */
1019 bp += strlen(bp);
1020 if (CurHostName != NULL)
1022 if (errnum == ETIMEDOUT)
1024 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1025 " with ");
1026 bp += strlen(bp);
1028 else
1030 bp = buf;
1031 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1032 "Connection reset by ");
1033 bp += strlen(bp);
1035 (void) sm_strlcpy(bp,
1036 shortenstring(CurHostName, MAXSHORTSTR),
1037 SPACELEFT(buf, bp));
1038 bp += strlen(buf);
1040 if (SmtpPhase != NULL)
1042 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1043 " during %s", SmtpPhase);
1045 return buf;
1047 case EHOSTDOWN:
1048 if (CurHostName == NULL)
1049 break;
1050 (void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
1051 shortenstring(CurHostName, MAXSHORTSTR));
1052 return buf;
1054 case ECONNREFUSED:
1055 if (CurHostName == NULL)
1056 break;
1057 (void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
1058 shortenstring(CurHostName, MAXSHORTSTR));
1059 return buf;
1061 #if NAMED_BIND
1062 case HOST_NOT_FOUND + E_DNSBASE:
1063 dnsmsg = "host not found";
1064 break;
1066 case TRY_AGAIN + E_DNSBASE:
1067 dnsmsg = "host name lookup failure";
1068 break;
1070 case NO_RECOVERY + E_DNSBASE:
1071 dnsmsg = "non-recoverable error";
1072 break;
1074 case NO_DATA + E_DNSBASE:
1075 dnsmsg = "no data known";
1076 break;
1077 #endif /* NAMED_BIND */
1079 case EPERM:
1080 /* SunOS gives "Not owner" -- this is the POSIX message */
1081 return "Operation not permitted";
1084 ** Error messages used internally in sendmail.
1087 case E_SM_OPENTIMEOUT:
1088 return "Timeout on file open";
1090 case E_SM_NOSLINK:
1091 return "Symbolic links not allowed";
1093 case E_SM_NOHLINK:
1094 return "Hard links not allowed";
1096 case E_SM_REGONLY:
1097 return "Regular files only";
1099 case E_SM_ISEXEC:
1100 return "Executable files not allowed";
1102 case E_SM_WWDIR:
1103 return "World writable directory";
1105 case E_SM_GWDIR:
1106 return "Group writable directory";
1108 case E_SM_FILECHANGE:
1109 return "File changed after open";
1111 case E_SM_WWFILE:
1112 return "World writable file";
1114 case E_SM_GWFILE:
1115 return "Group writable file";
1117 case E_SM_GRFILE:
1118 return "Group readable file";
1120 case E_SM_WRFILE:
1121 return "World readable file";
1124 if (dnsmsg != NULL)
1126 bp = buf;
1127 bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
1128 if (CurHostName != NULL)
1130 (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
1131 shortenstring(CurHostName, MAXSHORTSTR), ": ");
1132 bp += strlen(bp);
1134 (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1135 return buf;
1138 #if LDAPMAP
1139 if (errnum >= E_LDAPBASE)
1140 return ldap_err2string(errnum - E_LDAPBASE);
1141 #endif /* LDAPMAP */
1143 #if HASSTRERROR
1144 err = strerror(errnum);
1145 if (err == NULL)
1147 (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
1148 return buf;
1150 return err;
1151 #else /* HASSTRERROR */
1152 if (errnum > 0 && errnum < sys_nerr)
1153 return sys_errlist[errnum];
1155 (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
1156 return buf;
1157 #endif /* HASSTRERROR */