2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
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.
16 SM_RCSID("@(#)$Id: err.c,v 8.191 2003/01/10 02:16:46 ca Exp $")
20 # include <ldap.h> /* for LDAP error codes */
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 "!".
44 ** exc -- exception which is terminating this process
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.
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.
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
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.
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
104 ** Raises E:mta.quickabort if QuickAbort is set.
107 ** increments Errors.
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) */
121 syserr(const char *fmt, ...)
123 syserr(fmt, va_alist)
126 #endif /* __STDC__ */
129 int save_errno = errno;
157 /* format and output the error message */
161 ** Since we are terminating the process,
162 ** we are aborting the entire SMTP session,
163 ** rather than just the current transaction.
169 else if (save_errno == 0)
179 SM_VA_START(ap, fmt);
180 errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
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)
198 ExitStat = EX_SOFTWARE;
202 sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
205 pw = sm_getpwuid(RealUid);
211 (void) sm_snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid);
215 sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
216 CurEnv == NULL ? NOQID : CurEnv->e_id,
217 "SYSERR(%s): %.900s",
241 mci_dump_all(smioout, true);
256 sm_exc_raisenew_x(&EtypeQuickAbort, 2);
259 ** USRERR -- Signal user error.
261 ** This is much like syserr except it is for user errors.
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
270 ** Raises E:mta.quickabort if QuickAbort is set.
273 ** increments Errors.
279 usrerr(const char *fmt, ...)
281 usrerr(fmt, va_alist)
284 #endif /* __STDC__ */
290 if (fmt[0] == '5' || fmt[0] == '6')
292 else if (fmt[0] == '4' || fmt[0] == '8')
294 else if (fmt[0] == '2')
298 SM_VA_START(ap, fmt);
299 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
305 /* save this message for mailq printing */
310 if (CurEnv->e_message != NULL)
317 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
318 sm_free(CurEnv->e_message);
319 if (MsgBuf[0] == '6')
323 (void) sm_snprintf(buf, sizeof buf,
324 "Postmaster warning: %.*s",
325 (int) sizeof buf - 22, errtxt);
327 sm_rpool_strdup_x(CurEnv->e_rpool, buf);
332 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
338 if (LogLevel > 3 && LogUsrErrs)
339 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
341 sm_exc_raisenew_x(&EtypeQuickAbort, 1);
344 ** USRERRENH -- Signal user error.
346 ** Same as usrerr but with enhanced status code.
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
356 ** Raises E:mta.quickabort if QuickAbort is set.
359 ** increments Errors.
365 usrerrenh(char *enhsc, const char *fmt, ...)
367 usrerrenh(enhsc, fmt, va_alist)
371 #endif /* __STDC__ */
376 if (enhsc == NULL || *enhsc == '\0')
378 if (fmt[0] == '5' || fmt[0] == '6')
380 else if (fmt[0] == '4' || fmt[0] == '8')
382 else if (fmt[0] == '2')
385 SM_VA_START(ap, fmt);
386 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
392 /* save this message for mailq printing */
397 if (CurEnv->e_message != NULL)
404 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
405 sm_free(CurEnv->e_message);
406 if (MsgBuf[0] == '6')
410 (void) sm_snprintf(buf, sizeof buf,
411 "Postmaster warning: %.*s",
412 (int) sizeof buf - 22, errtxt);
414 sm_rpool_strdup_x(CurEnv->e_rpool, buf);
419 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
425 if (LogLevel > 3 && LogUsrErrs)
426 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
428 sm_exc_raisenew_x(&EtypeQuickAbort, 1);
431 ** MESSAGE -- print message (not necessarily an error)
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
448 message(const char *msg, ...)
450 message(msg, va_alist)
453 #endif /* __STDC__ */
459 SM_VA_START(ap, msg);
460 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
462 putoutmsg(MsgBuf, false, false);
464 /* save this message for mailq printing */
469 if (CurEnv->e_message != NULL)
474 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
475 sm_free(CurEnv->e_message);
477 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
482 ** NMESSAGE -- print message (not necessarily an error)
484 ** Just like "message" except it never puts the to... tag on.
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
502 nmessage(const char *msg, ...)
504 nmessage(msg, va_alist)
507 #endif /* __STDC__ */
513 SM_VA_START(ap, msg);
514 errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
515 (char *) NULL, 0, msg, ap);
517 putoutmsg(MsgBuf, false, false);
519 /* save this message for mailq printing */
524 if (CurEnv->e_message != NULL)
529 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
530 sm_free(CurEnv->e_message);
532 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
537 ** PUTOUTMSG -- output error message to transcript and channel
540 ** msg -- message to output (in SMTP format).
541 ** holdmsg -- if true, don't output a copy of the message to
542 ** our output channel.
543 ** heldmsg -- if true, this is a previously held message;
544 ** don't log it to the transcript file.
550 ** Outputs msg to the transcript.
551 ** If appropriate, outputs it to the channel.
552 ** Deletes SMTP reply code number as appropriate.
556 putoutmsg(msg, holdmsg, heldmsg)
562 char msgcode = msg[0];
564 /* display for debugging */
566 sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
567 heldmsg ? " (held)" : "");
569 /* map warnings to something SMTP can handle */
572 else if (msgcode == '8')
575 /* output to transcript if serious */
576 if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
577 strchr("45", msg[0]) != NULL)
578 (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
581 if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
582 sm_syslog(LOG_INFO, CurEnv->e_id,
583 "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
584 heldmsg ? " (held)" : "");
589 /* output to channel if appropriate */
590 if (!Verbose && msg[0] == '0')
594 /* save for possible future display */
596 if (HeldMessageBuf[0] == '5' && msgcode == '4')
598 (void) sm_strlcpy(HeldMessageBuf, msg, sizeof HeldMessageBuf);
602 (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
604 if (OutChannel == NULL)
607 /* find actual text of error (after SMTP status codes) */
608 if (ISSMTPREPLY(errtxt))
613 l = isenhsc(errtxt, ' ');
615 l = isenhsc(errtxt, '\0');
620 /* if DisConnected, OutChannel now points to the transcript */
622 (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
623 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
626 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
628 if (TrafficLogFile != NULL)
629 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
630 "%05d >>> %s\n", (int) CurrentPid,
631 (OpMode == MD_SMTP || OpMode == MD_DAEMON)
634 /* XXX can't flush here for SMTP pipelining */
636 (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
637 if (!sm_io_error(OutChannel) || DisConnected)
641 ** Error on output -- if reporting lost channel, just ignore it.
642 ** Also, ignore errors from QUIT response (221 message) -- some
643 ** rude servers don't read result.
646 if (InChannel == NULL || sm_io_eof(InChannel) ||
647 sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
650 /* can't call syserr, 'cause we are using MsgBuf */
653 sm_syslog(LOG_CRIT, CurEnv->e_id,
654 "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
656 shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
657 #endif /* !PIPELINING */
660 ** PUTERRMSG -- like putoutmsg, but does special processing for error messages
663 ** msg -- the message to output.
669 ** Sets the fatal error bit in the envelope as appropriate.
676 char msgcode = msg[0];
678 /* output the message as usual */
679 putoutmsg(msg, HoldErrs, false);
681 /* be careful about multiple error messages */
685 /* signal the error */
693 /* notify the postmaster */
694 CurEnv->e_flags |= EF_PM_NOTIFY;
696 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
698 /* mark long-term fatal errors */
699 CurEnv->e_flags |= EF_FATALERRS;
703 ** ISENHSC -- check whether a string contains an enhanced status code
706 ** s -- string with possible enhanced status code.
707 ** delim -- delim for enhanced status code.
710 ** 0 -- no enhanced status code.
711 ** >4 -- length of enhanced status code.
725 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
729 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
731 if (h == 0 || s[l + h] != '.')
735 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
737 if (h == 0 || s[l + h] != delim)
742 ** EXTENHSC -- check and extract an enhanced status code
745 ** s -- string with possible enhanced status code.
746 ** delim -- delim for enhanced status code.
747 ** e -- pointer to storage for enhanced status code.
748 ** must be != NULL and have space for at least
749 ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
752 ** 0 -- no enhanced status code.
753 ** >4 -- length of enhanced status code.
756 ** fills e with enhanced status code.
760 extenhsc(s, delim, e)
769 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
775 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
780 if (h == 0 || s[l + h] != '.')
785 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
790 if (h == 0 || s[l + h] != delim)
796 ** FMTMSG -- format a message into buffer.
799 ** eb -- error buffer to get result -- MUST BE MsgBuf.
800 ** to -- the recipient tag for this message.
801 ** num -- default three digit SMTP reply code.
802 ** enhsc -- enhanced status code.
803 ** en -- the error number to display.
804 ** fmt -- format of string.
805 ** ap -- arguments for fmt.
808 ** pointer to error text beyond status codes.
815 fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
826 int spaceleft = sizeof MsgBuf;
829 /* output the reply code */
840 if (SoftBounce && num[0] == '5')
843 (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
846 #endif /* _FFR_SOFT_BOUNCE */
847 (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
851 if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
853 /* copy enh.status code including trailing blank */
855 (void) sm_strlcpy(eb, fmt, l + 1);
860 else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
862 /* copy enh.status code */
863 (void) sm_strlcpy(eb, enhsc, l + 1);
870 if (SoftBounce && eb[-l] == '5')
875 #endif /* _FFR_SOFT_BOUNCE */
878 /* output the file name and line number */
879 if (FileName != NULL)
881 (void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
882 shortenstring(FileName, 83), LineNumber);
883 eb += (l = strlen(eb));
888 ** output the "to" address only if it is defined and one of the
889 ** following codes is used:
890 ** 050 internal notices, e.g., alias expansion
892 ** 252 Cannot VRFY user, but will accept message and attempt delivery
893 ** 450 Requested mail action not taken: mailbox unavailable
894 ** 550 Requested action not taken: mailbox unavailable
895 ** 553 Requested action not taken: mailbox name not allowed
897 ** Notice: this still isn't "the right thing", this code shouldn't
898 ** (indirectly) depend on CurEnv->e_to.
901 if (to != NULL && to[0] != '\0' &&
902 (strncmp(num, "050", 3) == 0 ||
903 strncmp(num, "250", 3) == 0 ||
904 strncmp(num, "252", 3) == 0 ||
905 strncmp(num, "450", 3) == 0 ||
906 strncmp(num, "550", 3) == 0 ||
907 strncmp(num, "553", 3) == 0))
909 (void) sm_strlcpyn(eb, spaceleft, 2,
910 shortenstring(to, MAXSHORTSTR), "... ");
911 spaceleft -= strlen(eb);
916 /* output the message */
917 (void) sm_vsnprintf(eb, spaceleft, fmt, ap);
918 spaceleft -= strlen(eb);
922 /* output the error code, if any */
924 (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
929 ** BUFFER_ERRORS -- arrange to buffer future error messages
941 HeldMessageBuf[0] = '\0';
945 ** FLUSH_ERRORS -- flush the held error message buffer
948 ** print -- if set, print the message, otherwise just
959 if (print && HeldMessageBuf[0] != '\0')
960 putoutmsg(HeldMessageBuf, false, true);
961 HeldMessageBuf[0] = '\0';
965 ** SM_ERRSTRING -- return string description of error code
968 ** errnum -- the error number to translate
971 ** A string description of errnum.
983 static char buf[MAXLINE];
987 #endif /* HASSTRERROR */
988 #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
989 extern char *sys_errlist[];
991 #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
994 ** Handle special network error codes.
996 ** These are 4.2/4.3bsd specific; they should be in daemon.c.
1006 err = strerror(errnum);
1009 (void) sm_snprintf(errbuf, sizeof errbuf,
1010 "Error %d", errnum);
1013 (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
1014 #else /* HASSTRERROR */
1015 if (errnum >= 0 && errnum < sys_nerr)
1016 (void) sm_strlcpy(bp, sys_errlist[errnum],
1017 SPACELEFT(buf, bp));
1019 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1020 "Error %d", errnum);
1021 #endif /* HASSTRERROR */
1023 if (CurHostName != NULL)
1025 if (errnum == ETIMEDOUT)
1027 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1034 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1035 "Connection reset by ");
1038 (void) sm_strlcpy(bp,
1039 shortenstring(CurHostName, MAXSHORTSTR),
1040 SPACELEFT(buf, bp));
1043 if (SmtpPhase != NULL)
1045 (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1046 " during %s", SmtpPhase);
1051 if (CurHostName == NULL)
1053 (void) sm_snprintf(buf, sizeof buf, "Host %s is down",
1054 shortenstring(CurHostName, MAXSHORTSTR));
1058 if (CurHostName == NULL)
1060 (void) sm_strlcpyn(buf, sizeof buf, 2, "Connection refused by ",
1061 shortenstring(CurHostName, MAXSHORTSTR));
1065 case HOST_NOT_FOUND + E_DNSBASE:
1066 dnsmsg = "host not found";
1069 case TRY_AGAIN + E_DNSBASE:
1070 dnsmsg = "host name lookup failure";
1073 case NO_RECOVERY + E_DNSBASE:
1074 dnsmsg = "non-recoverable error";
1077 case NO_DATA + E_DNSBASE:
1078 dnsmsg = "no data known";
1080 #endif /* NAMED_BIND */
1083 /* SunOS gives "Not owner" -- this is the POSIX message */
1084 return "Operation not permitted";
1087 ** Error messages used internally in sendmail.
1090 case E_SM_OPENTIMEOUT:
1091 return "Timeout on file open";
1094 return "Symbolic links not allowed";
1097 return "Hard links not allowed";
1100 return "Regular files only";
1103 return "Executable files not allowed";
1106 return "World writable directory";
1109 return "Group writable directory";
1111 case E_SM_FILECHANGE:
1112 return "File changed after open";
1115 return "World writable file";
1118 return "Group writable file";
1121 return "Group readable file";
1124 return "World readable file";
1130 bp += sm_strlcpy(bp, "Name server: ", sizeof buf);
1131 if (CurHostName != NULL)
1133 (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
1134 shortenstring(CurHostName, MAXSHORTSTR), ": ");
1137 (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1142 if (errnum >= E_LDAPBASE)
1143 return ldap_err2string(errnum - E_LDAPBASE);
1144 #endif /* LDAPMAP */
1147 err = strerror(errnum);
1150 (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
1154 #else /* HASSTRERROR */
1155 if (errnum > 0 && errnum < sys_nerr)
1156 return sys_errlist[errnum];
1158 (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
1160 #endif /* HASSTRERROR */