1c2aa98e2SPeter Wemm /*
25b0945b5SGregory Neil Shapiro * Copyright (c) 1998-2003, 2010, 2015 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro * All rights reserved.
4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved.
7c2aa98e2SPeter Wemm *
8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm * the sendmail distribution.
11c2aa98e2SPeter Wemm *
12c2aa98e2SPeter Wemm */
13c2aa98e2SPeter Wemm
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
1512ed1c7cSGregory Neil Shapiro
164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: err.c,v 8.206 2013-11-22 20:51:55 ca Exp $")
17c2aa98e2SPeter Wemm
1812ed1c7cSGregory Neil Shapiro #if LDAPMAP
193299c2f1SGregory Neil Shapiro # include <lber.h>
203299c2f1SGregory Neil Shapiro # include <ldap.h> /* for LDAP error codes */
215b0945b5SGregory Neil Shapiro #endif
22*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
23*2fb4f839SGregory Neil Shapiro # include <sm/sendmail.h>
24*2fb4f839SGregory Neil Shapiro #endif
253299c2f1SGregory Neil Shapiro
263299c2f1SGregory Neil Shapiro static void putoutmsg __P((char *, bool, bool));
273299c2f1SGregory Neil Shapiro static void puterrmsg __P((char *));
283299c2f1SGregory Neil Shapiro static char *fmtmsg __P((char *, const char *, const char *, const char *,
293299c2f1SGregory Neil Shapiro int, const char *, va_list));
30c2aa98e2SPeter Wemm
31c2aa98e2SPeter Wemm /*
3212ed1c7cSGregory Neil Shapiro ** FATAL_ERROR -- handle a fatal exception
3312ed1c7cSGregory Neil Shapiro **
3412ed1c7cSGregory Neil Shapiro ** This function is installed as the default exception handler
3512ed1c7cSGregory Neil Shapiro ** in the main sendmail process, and in all child processes
3612ed1c7cSGregory Neil Shapiro ** that we create. Its job is to handle exceptions that are not
3712ed1c7cSGregory Neil Shapiro ** handled at a lower level.
3812ed1c7cSGregory Neil Shapiro **
3912ed1c7cSGregory Neil Shapiro ** The theory is that unhandled exceptions will be 'fatal' class
4012ed1c7cSGregory Neil Shapiro ** exceptions (with an "F:" prefix), such as the out-of-memory
4112ed1c7cSGregory Neil Shapiro ** exception "F:sm.heap". As such, they are handled by exiting
4212ed1c7cSGregory Neil Shapiro ** the process in exactly the same way that xalloc() in Sendmail 8.10
4312ed1c7cSGregory Neil Shapiro ** exits the process when it fails due to lack of memory:
4412ed1c7cSGregory Neil Shapiro ** we call syserr with a message beginning with "!".
4512ed1c7cSGregory Neil Shapiro **
4612ed1c7cSGregory Neil Shapiro ** Parameters:
4712ed1c7cSGregory Neil Shapiro ** exc -- exception which is terminating this process
4812ed1c7cSGregory Neil Shapiro **
4912ed1c7cSGregory Neil Shapiro ** Returns:
5012ed1c7cSGregory Neil Shapiro ** none
5112ed1c7cSGregory Neil Shapiro */
5212ed1c7cSGregory Neil Shapiro
5312ed1c7cSGregory Neil Shapiro void
fatal_error(exc)5412ed1c7cSGregory Neil Shapiro fatal_error(exc)
5512ed1c7cSGregory Neil Shapiro SM_EXC_T *exc;
5612ed1c7cSGregory Neil Shapiro {
5712ed1c7cSGregory Neil Shapiro static char buf[256];
5812ed1c7cSGregory Neil Shapiro SM_FILE_T f;
5912ed1c7cSGregory Neil Shapiro
6012ed1c7cSGregory Neil Shapiro /*
6112ed1c7cSGregory Neil Shapiro ** This function may be called when the heap is exhausted.
6212ed1c7cSGregory Neil Shapiro ** The following code writes the message for 'exc' into our
6312ed1c7cSGregory Neil Shapiro ** static buffer without allocating memory or raising exceptions.
6412ed1c7cSGregory Neil Shapiro */
6512ed1c7cSGregory Neil Shapiro
6612ed1c7cSGregory Neil Shapiro sm_strio_init(&f, buf, sizeof(buf));
6712ed1c7cSGregory Neil Shapiro sm_exc_write(exc, &f);
6812ed1c7cSGregory Neil Shapiro (void) sm_io_flush(&f, SM_TIME_DEFAULT);
6912ed1c7cSGregory Neil Shapiro
7012ed1c7cSGregory Neil Shapiro /*
7112ed1c7cSGregory Neil Shapiro ** Terminate the process after logging an error and cleaning up.
7212ed1c7cSGregory Neil Shapiro ** Problems:
7312ed1c7cSGregory Neil Shapiro ** - syserr decides what class of error this is by looking at errno.
7412ed1c7cSGregory Neil Shapiro ** That's no good; we should look at the exc structure.
7512ed1c7cSGregory Neil Shapiro ** - The cleanup code should be moved out of syserr
7612ed1c7cSGregory Neil Shapiro ** and into individual exception handlers
7712ed1c7cSGregory Neil Shapiro ** that are part of the module they clean up after.
7812ed1c7cSGregory Neil Shapiro */
7912ed1c7cSGregory Neil Shapiro
8012ed1c7cSGregory Neil Shapiro errno = ENOMEM;
8112ed1c7cSGregory Neil Shapiro syserr("!%s", buf);
8212ed1c7cSGregory Neil Shapiro }
8312ed1c7cSGregory Neil Shapiro
8412ed1c7cSGregory Neil Shapiro /*
85c2aa98e2SPeter Wemm ** SYSERR -- Print error message.
86c2aa98e2SPeter Wemm **
8712ed1c7cSGregory Neil Shapiro ** Prints an error message via sm_io_printf to the diagnostic output.
88c2aa98e2SPeter Wemm **
89c2aa98e2SPeter Wemm ** If the first character of the syserr message is `!' it will
90c2aa98e2SPeter Wemm ** log this as an ALERT message and exit immediately. This can
91c2aa98e2SPeter Wemm ** leave queue files in an indeterminate state, so it should not
92c2aa98e2SPeter Wemm ** be used lightly.
93c2aa98e2SPeter Wemm **
9412ed1c7cSGregory Neil Shapiro ** If the first character of the syserr message is '!' or '@'
9512ed1c7cSGregory Neil Shapiro ** then syserr knows that the process is about to be terminated,
9612ed1c7cSGregory Neil Shapiro ** so the SMTP reply code defaults to 421. Otherwise, the
9712ed1c7cSGregory Neil Shapiro ** reply code defaults to 451 or 554, depending on errno.
9812ed1c7cSGregory Neil Shapiro **
99c2aa98e2SPeter Wemm ** Parameters:
100da7d7b9cSGregory Neil Shapiro ** fmt -- the format string. An optional '!', '@', or '+',
10112ed1c7cSGregory Neil Shapiro ** followed by an optional three-digit SMTP
10212ed1c7cSGregory Neil Shapiro ** reply code, followed by message text.
103c2aa98e2SPeter Wemm ** (others) -- parameters
104c2aa98e2SPeter Wemm **
105c2aa98e2SPeter Wemm ** Returns:
106c2aa98e2SPeter Wemm ** none
10712ed1c7cSGregory Neil Shapiro ** Raises E:mta.quickabort if QuickAbort is set.
108c2aa98e2SPeter Wemm **
109c2aa98e2SPeter Wemm ** Side Effects:
110c2aa98e2SPeter Wemm ** increments Errors.
111c2aa98e2SPeter Wemm ** sets ExitStat.
112c2aa98e2SPeter Wemm */
113c2aa98e2SPeter Wemm
114c2aa98e2SPeter Wemm char MsgBuf[BUFSIZ*2]; /* text of most recent message */
115951742c4SGregory Neil Shapiro static char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */
116c2aa98e2SPeter Wemm
117c2aa98e2SPeter Wemm void
118c2aa98e2SPeter Wemm /*VARARGS1*/
119c2aa98e2SPeter Wemm #ifdef __STDC__
syserr(const char * fmt,...)120c2aa98e2SPeter Wemm syserr(const char *fmt, ...)
1213299c2f1SGregory Neil Shapiro #else /* __STDC__ */
122c2aa98e2SPeter Wemm syserr(fmt, va_alist)
123c2aa98e2SPeter Wemm const char *fmt;
124c2aa98e2SPeter Wemm va_dcl
1253299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
126c2aa98e2SPeter Wemm {
127c2aa98e2SPeter Wemm register char *p;
1283299c2f1SGregory Neil Shapiro int save_errno = errno;
129da7d7b9cSGregory Neil Shapiro bool panic, exiting, keep;
1303299c2f1SGregory Neil Shapiro char *user;
1313299c2f1SGregory Neil Shapiro char *enhsc;
1323299c2f1SGregory Neil Shapiro char *errtxt;
133c2aa98e2SPeter Wemm struct passwd *pw;
134c2aa98e2SPeter Wemm char ubuf[80];
13512ed1c7cSGregory Neil Shapiro SM_VA_LOCAL_DECL
136c2aa98e2SPeter Wemm
137da7d7b9cSGregory Neil Shapiro panic = exiting = keep = false;
13812ed1c7cSGregory Neil Shapiro switch (*fmt)
139c2aa98e2SPeter Wemm {
14012ed1c7cSGregory Neil Shapiro case '!':
14112ed1c7cSGregory Neil Shapiro ++fmt;
142da7d7b9cSGregory Neil Shapiro panic = exiting = true;
14312ed1c7cSGregory Neil Shapiro break;
14412ed1c7cSGregory Neil Shapiro case '@':
14512ed1c7cSGregory Neil Shapiro ++fmt;
14612ed1c7cSGregory Neil Shapiro exiting = true;
14712ed1c7cSGregory Neil Shapiro break;
148da7d7b9cSGregory Neil Shapiro case '+':
149da7d7b9cSGregory Neil Shapiro ++fmt;
150da7d7b9cSGregory Neil Shapiro keep = true;
151da7d7b9cSGregory Neil Shapiro break;
15212ed1c7cSGregory Neil Shapiro default:
15312ed1c7cSGregory Neil Shapiro break;
154c2aa98e2SPeter Wemm }
155c2aa98e2SPeter Wemm
156c2aa98e2SPeter Wemm /* format and output the error message */
15712ed1c7cSGregory Neil Shapiro if (exiting)
15812ed1c7cSGregory Neil Shapiro {
15912ed1c7cSGregory Neil Shapiro /*
16012ed1c7cSGregory Neil Shapiro ** Since we are terminating the process,
16112ed1c7cSGregory Neil Shapiro ** we are aborting the entire SMTP session,
16212ed1c7cSGregory Neil Shapiro ** rather than just the current transaction.
16312ed1c7cSGregory Neil Shapiro */
16412ed1c7cSGregory Neil Shapiro
16512ed1c7cSGregory Neil Shapiro p = "421";
16612ed1c7cSGregory Neil Shapiro enhsc = "4.0.0";
16712ed1c7cSGregory Neil Shapiro }
16812ed1c7cSGregory Neil Shapiro else if (save_errno == 0)
1693299c2f1SGregory Neil Shapiro {
170c2aa98e2SPeter Wemm p = "554";
1713299c2f1SGregory Neil Shapiro enhsc = "5.0.0";
1723299c2f1SGregory Neil Shapiro }
173c2aa98e2SPeter Wemm else
1743299c2f1SGregory Neil Shapiro {
175c2aa98e2SPeter Wemm p = "451";
1763299c2f1SGregory Neil Shapiro enhsc = "4.0.0";
1773299c2f1SGregory Neil Shapiro }
17812ed1c7cSGregory Neil Shapiro SM_VA_START(ap, fmt);
1793299c2f1SGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
18012ed1c7cSGregory Neil Shapiro SM_VA_END(ap);
181c2aa98e2SPeter Wemm puterrmsg(MsgBuf);
182c2aa98e2SPeter Wemm
183c2aa98e2SPeter Wemm /* save this message for mailq printing */
184da7d7b9cSGregory Neil Shapiro if (!panic && CurEnv != NULL && (!keep || CurEnv->e_message == NULL))
185c2aa98e2SPeter Wemm {
18612ed1c7cSGregory Neil Shapiro char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
18712ed1c7cSGregory Neil Shapiro
18812ed1c7cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
189c0c4794dSGregory Neil Shapiro sm_free(CurEnv->e_message);
19012ed1c7cSGregory Neil Shapiro CurEnv->e_message = nmsg;
191c2aa98e2SPeter Wemm }
192c2aa98e2SPeter Wemm
193c2aa98e2SPeter Wemm /* determine exit status if not already set */
194c2aa98e2SPeter Wemm if (ExitStat == EX_OK)
195c2aa98e2SPeter Wemm {
1963299c2f1SGregory Neil Shapiro if (save_errno == 0)
197c2aa98e2SPeter Wemm ExitStat = EX_SOFTWARE;
198c2aa98e2SPeter Wemm else
199c2aa98e2SPeter Wemm ExitStat = EX_OSERR;
200c2aa98e2SPeter Wemm if (tTd(54, 1))
20112ed1c7cSGregory Neil Shapiro sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
202c2aa98e2SPeter Wemm }
203c2aa98e2SPeter Wemm
204c0c4794dSGregory Neil Shapiro pw = sm_getpwuid(RealUid);
205c2aa98e2SPeter Wemm if (pw != NULL)
2063299c2f1SGregory Neil Shapiro user = pw->pw_name;
207c2aa98e2SPeter Wemm else
208c2aa98e2SPeter Wemm {
2093299c2f1SGregory Neil Shapiro user = ubuf;
210951742c4SGregory Neil Shapiro (void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid);
211c2aa98e2SPeter Wemm }
212c2aa98e2SPeter Wemm
213c2aa98e2SPeter Wemm if (LogLevel > 0)
214c2aa98e2SPeter Wemm sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
215c2aa98e2SPeter Wemm CurEnv == NULL ? NOQID : CurEnv->e_id,
216c2aa98e2SPeter Wemm "SYSERR(%s): %.900s",
2173299c2f1SGregory Neil Shapiro user, errtxt);
2183299c2f1SGregory Neil Shapiro switch (save_errno)
219c2aa98e2SPeter Wemm {
220c2aa98e2SPeter Wemm case EBADF:
221c2aa98e2SPeter Wemm case ENFILE:
222c2aa98e2SPeter Wemm case EMFILE:
223c2aa98e2SPeter Wemm case ENOTTY:
224c2aa98e2SPeter Wemm #ifdef EFBIG
225c2aa98e2SPeter Wemm case EFBIG:
2265b0945b5SGregory Neil Shapiro #endif
227c2aa98e2SPeter Wemm #ifdef ESPIPE
228c2aa98e2SPeter Wemm case ESPIPE:
2295b0945b5SGregory Neil Shapiro #endif
230c2aa98e2SPeter Wemm #ifdef EPIPE
231c2aa98e2SPeter Wemm case EPIPE:
2325b0945b5SGregory Neil Shapiro #endif
233c2aa98e2SPeter Wemm #ifdef ENOBUFS
234c2aa98e2SPeter Wemm case ENOBUFS:
2355b0945b5SGregory Neil Shapiro #endif
236c2aa98e2SPeter Wemm #ifdef ESTALE
237c2aa98e2SPeter Wemm case ESTALE:
2385b0945b5SGregory Neil Shapiro #endif
23912ed1c7cSGregory Neil Shapiro printopenfds(true);
240bfb62e91SGregory Neil Shapiro mci_dump_all(smioout, true);
241c2aa98e2SPeter Wemm break;
242c2aa98e2SPeter Wemm }
243c2aa98e2SPeter Wemm if (panic)
244c2aa98e2SPeter Wemm {
24512ed1c7cSGregory Neil Shapiro #if XLA
246c2aa98e2SPeter Wemm xla_all_end();
2475b0945b5SGregory Neil Shapiro #endif
2483299c2f1SGregory Neil Shapiro sync_queue_time();
249c2aa98e2SPeter Wemm if (tTd(0, 1))
250c2aa98e2SPeter Wemm abort();
251c2aa98e2SPeter Wemm exit(EX_OSERR);
252c2aa98e2SPeter Wemm }
253c2aa98e2SPeter Wemm errno = 0;
254c2aa98e2SPeter Wemm if (QuickAbort)
25512ed1c7cSGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2);
256c2aa98e2SPeter Wemm }
2575b0945b5SGregory Neil Shapiro
25812ed1c7cSGregory Neil Shapiro /*
259c2aa98e2SPeter Wemm ** USRERR -- Signal user error.
260c2aa98e2SPeter Wemm **
261c2aa98e2SPeter Wemm ** This is much like syserr except it is for user errors.
262c2aa98e2SPeter Wemm **
263c2aa98e2SPeter Wemm ** Parameters:
264c2aa98e2SPeter Wemm ** fmt -- the format string. If it does not begin with
26512ed1c7cSGregory Neil Shapiro ** a three-digit SMTP reply code, 550 is assumed.
26612ed1c7cSGregory Neil Shapiro ** (others) -- sm_io_printf strings
267c2aa98e2SPeter Wemm **
268c2aa98e2SPeter Wemm ** Returns:
269c2aa98e2SPeter Wemm ** none
27012ed1c7cSGregory Neil Shapiro ** Raises E:mta.quickabort if QuickAbort is set.
271c2aa98e2SPeter Wemm **
272c2aa98e2SPeter Wemm ** Side Effects:
273c2aa98e2SPeter Wemm ** increments Errors.
274c2aa98e2SPeter Wemm */
275c2aa98e2SPeter Wemm
276c2aa98e2SPeter Wemm /*VARARGS1*/
277c2aa98e2SPeter Wemm void
278c2aa98e2SPeter Wemm #ifdef __STDC__
usrerr(const char * fmt,...)279c2aa98e2SPeter Wemm usrerr(const char *fmt, ...)
2803299c2f1SGregory Neil Shapiro #else /* __STDC__ */
281c2aa98e2SPeter Wemm usrerr(fmt, va_alist)
282c2aa98e2SPeter Wemm const char *fmt;
283c2aa98e2SPeter Wemm va_dcl
2843299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
285c2aa98e2SPeter Wemm {
2863299c2f1SGregory Neil Shapiro char *enhsc;
2873299c2f1SGregory Neil Shapiro char *errtxt;
28812ed1c7cSGregory Neil Shapiro SM_VA_LOCAL_DECL
289c2aa98e2SPeter Wemm
2903299c2f1SGregory Neil Shapiro if (fmt[0] == '5' || fmt[0] == '6')
2913299c2f1SGregory Neil Shapiro enhsc = "5.0.0";
2923299c2f1SGregory Neil Shapiro else if (fmt[0] == '4' || fmt[0] == '8')
2933299c2f1SGregory Neil Shapiro enhsc = "4.0.0";
2943299c2f1SGregory Neil Shapiro else if (fmt[0] == '2')
2953299c2f1SGregory Neil Shapiro enhsc = "2.0.0";
2963299c2f1SGregory Neil Shapiro else
2973299c2f1SGregory Neil Shapiro enhsc = NULL;
29812ed1c7cSGregory Neil Shapiro SM_VA_START(ap, fmt);
29912ed1c7cSGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
30012ed1c7cSGregory Neil Shapiro SM_VA_END(ap);
3013299c2f1SGregory Neil Shapiro
302c2aa98e2SPeter Wemm if (SuprErrs)
303c2aa98e2SPeter Wemm return;
304c2aa98e2SPeter Wemm
305c2aa98e2SPeter Wemm /* save this message for mailq printing */
306c2aa98e2SPeter Wemm switch (MsgBuf[0])
307c2aa98e2SPeter Wemm {
308c2aa98e2SPeter Wemm case '4':
309c2aa98e2SPeter Wemm case '8':
310c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL)
311c2aa98e2SPeter Wemm break;
312c2aa98e2SPeter Wemm
3133299c2f1SGregory Neil Shapiro /* FALLTHROUGH */
314c2aa98e2SPeter Wemm
315c2aa98e2SPeter Wemm case '5':
316c2aa98e2SPeter Wemm case '6':
31712ed1c7cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
318c0c4794dSGregory Neil Shapiro sm_free(CurEnv->e_message);
319c2aa98e2SPeter Wemm if (MsgBuf[0] == '6')
320c2aa98e2SPeter Wemm {
321c2aa98e2SPeter Wemm char buf[MAXLINE];
322c2aa98e2SPeter Wemm
323951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf),
32412ed1c7cSGregory Neil Shapiro "Postmaster warning: %.*s",
325951742c4SGregory Neil Shapiro (int) sizeof(buf) - 22, errtxt);
32612ed1c7cSGregory Neil Shapiro CurEnv->e_message =
32712ed1c7cSGregory Neil Shapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf);
328c2aa98e2SPeter Wemm }
329c2aa98e2SPeter Wemm else
330c2aa98e2SPeter Wemm {
33112ed1c7cSGregory Neil Shapiro CurEnv->e_message =
33212ed1c7cSGregory Neil Shapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
333c2aa98e2SPeter Wemm }
334c2aa98e2SPeter Wemm break;
335c2aa98e2SPeter Wemm }
336c2aa98e2SPeter Wemm
337c2aa98e2SPeter Wemm puterrmsg(MsgBuf);
338c2aa98e2SPeter Wemm if (LogLevel > 3 && LogUsrErrs)
3393299c2f1SGregory Neil Shapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
3403299c2f1SGregory Neil Shapiro if (QuickAbort)
34112ed1c7cSGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3423299c2f1SGregory Neil Shapiro }
3435b0945b5SGregory Neil Shapiro
34412ed1c7cSGregory Neil Shapiro /*
3453299c2f1SGregory Neil Shapiro ** USRERRENH -- Signal user error.
3463299c2f1SGregory Neil Shapiro **
3473299c2f1SGregory Neil Shapiro ** Same as usrerr but with enhanced status code.
3483299c2f1SGregory Neil Shapiro **
3493299c2f1SGregory Neil Shapiro ** Parameters:
3503299c2f1SGregory Neil Shapiro ** enhsc -- the enhanced status code.
3513299c2f1SGregory Neil Shapiro ** fmt -- the format string. If it does not begin with
35212ed1c7cSGregory Neil Shapiro ** a three-digit SMTP reply code, 550 is assumed.
35312ed1c7cSGregory Neil Shapiro ** (others) -- sm_io_printf strings
3543299c2f1SGregory Neil Shapiro **
3553299c2f1SGregory Neil Shapiro ** Returns:
3563299c2f1SGregory Neil Shapiro ** none
35712ed1c7cSGregory Neil Shapiro ** Raises E:mta.quickabort if QuickAbort is set.
3583299c2f1SGregory Neil Shapiro **
3593299c2f1SGregory Neil Shapiro ** Side Effects:
3603299c2f1SGregory Neil Shapiro ** increments Errors.
3613299c2f1SGregory Neil Shapiro */
3623299c2f1SGregory Neil Shapiro
3636f9c8e5bSGregory Neil Shapiro /*VARARGS2*/
3643299c2f1SGregory Neil Shapiro void
3653299c2f1SGregory Neil Shapiro #ifdef __STDC__
usrerrenh(char * enhsc,const char * fmt,...)3663299c2f1SGregory Neil Shapiro usrerrenh(char *enhsc, const char *fmt, ...)
3673299c2f1SGregory Neil Shapiro #else /* __STDC__ */
3683299c2f1SGregory Neil Shapiro usrerrenh(enhsc, fmt, va_alist)
3693299c2f1SGregory Neil Shapiro char *enhsc;
3703299c2f1SGregory Neil Shapiro const char *fmt;
3713299c2f1SGregory Neil Shapiro va_dcl
3723299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
3733299c2f1SGregory Neil Shapiro {
3743299c2f1SGregory Neil Shapiro char *errtxt;
37512ed1c7cSGregory Neil Shapiro SM_VA_LOCAL_DECL
3763299c2f1SGregory Neil Shapiro
377*2fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(enhsc))
3783299c2f1SGregory Neil Shapiro {
3793299c2f1SGregory Neil Shapiro if (fmt[0] == '5' || fmt[0] == '6')
3803299c2f1SGregory Neil Shapiro enhsc = "5.0.0";
3813299c2f1SGregory Neil Shapiro else if (fmt[0] == '4' || fmt[0] == '8')
3823299c2f1SGregory Neil Shapiro enhsc = "4.0.0";
3833299c2f1SGregory Neil Shapiro else if (fmt[0] == '2')
3843299c2f1SGregory Neil Shapiro enhsc = "2.0.0";
3853299c2f1SGregory Neil Shapiro }
38612ed1c7cSGregory Neil Shapiro SM_VA_START(ap, fmt);
38712ed1c7cSGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
38812ed1c7cSGregory Neil Shapiro SM_VA_END(ap);
3893299c2f1SGregory Neil Shapiro
3903299c2f1SGregory Neil Shapiro if (SuprErrs)
3913299c2f1SGregory Neil Shapiro return;
3923299c2f1SGregory Neil Shapiro
3933299c2f1SGregory Neil Shapiro /* save this message for mailq printing */
3943299c2f1SGregory Neil Shapiro switch (MsgBuf[0])
3953299c2f1SGregory Neil Shapiro {
3963299c2f1SGregory Neil Shapiro case '4':
3973299c2f1SGregory Neil Shapiro case '8':
3983299c2f1SGregory Neil Shapiro if (CurEnv->e_message != NULL)
3993299c2f1SGregory Neil Shapiro break;
4003299c2f1SGregory Neil Shapiro
4013299c2f1SGregory Neil Shapiro /* FALLTHROUGH */
4023299c2f1SGregory Neil Shapiro
4033299c2f1SGregory Neil Shapiro case '5':
4043299c2f1SGregory Neil Shapiro case '6':
40512ed1c7cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
406c0c4794dSGregory Neil Shapiro sm_free(CurEnv->e_message);
4073299c2f1SGregory Neil Shapiro if (MsgBuf[0] == '6')
4083299c2f1SGregory Neil Shapiro {
4093299c2f1SGregory Neil Shapiro char buf[MAXLINE];
4103299c2f1SGregory Neil Shapiro
411951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf),
41212ed1c7cSGregory Neil Shapiro "Postmaster warning: %.*s",
413951742c4SGregory Neil Shapiro (int) sizeof(buf) - 22, errtxt);
41412ed1c7cSGregory Neil Shapiro CurEnv->e_message =
41512ed1c7cSGregory Neil Shapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf);
4163299c2f1SGregory Neil Shapiro }
4173299c2f1SGregory Neil Shapiro else
4183299c2f1SGregory Neil Shapiro {
41912ed1c7cSGregory Neil Shapiro CurEnv->e_message =
42012ed1c7cSGregory Neil Shapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
4213299c2f1SGregory Neil Shapiro }
4223299c2f1SGregory Neil Shapiro break;
4233299c2f1SGregory Neil Shapiro }
4243299c2f1SGregory Neil Shapiro
4253299c2f1SGregory Neil Shapiro puterrmsg(MsgBuf);
4263299c2f1SGregory Neil Shapiro if (LogLevel > 3 && LogUsrErrs)
4273299c2f1SGregory Neil Shapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
428c2aa98e2SPeter Wemm if (QuickAbort)
42912ed1c7cSGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
430c2aa98e2SPeter Wemm }
4316f9c8e5bSGregory Neil Shapiro
43212ed1c7cSGregory Neil Shapiro /*
433c2aa98e2SPeter Wemm ** MESSAGE -- print message (not necessarily an error)
434c2aa98e2SPeter Wemm **
435c2aa98e2SPeter Wemm ** Parameters:
43612ed1c7cSGregory Neil Shapiro ** msg -- the message (sm_io_printf fmt) -- it can begin with
437c2aa98e2SPeter Wemm ** an SMTP reply code. If not, 050 is assumed.
43812ed1c7cSGregory Neil Shapiro ** (others) -- sm_io_printf arguments
439c2aa98e2SPeter Wemm **
440c2aa98e2SPeter Wemm ** Returns:
441c2aa98e2SPeter Wemm ** none
442c2aa98e2SPeter Wemm */
443c2aa98e2SPeter Wemm
444c2aa98e2SPeter Wemm /*VARARGS1*/
445c2aa98e2SPeter Wemm void
446c2aa98e2SPeter Wemm #ifdef __STDC__
message(const char * msg,...)447c2aa98e2SPeter Wemm message(const char *msg, ...)
4483299c2f1SGregory Neil Shapiro #else /* __STDC__ */
449c2aa98e2SPeter Wemm message(msg, va_alist)
450c2aa98e2SPeter Wemm const char *msg;
451c2aa98e2SPeter Wemm va_dcl
4523299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
453c2aa98e2SPeter Wemm {
4543299c2f1SGregory Neil Shapiro char *errtxt;
45512ed1c7cSGregory Neil Shapiro SM_VA_LOCAL_DECL
456c2aa98e2SPeter Wemm
457c2aa98e2SPeter Wemm errno = 0;
45812ed1c7cSGregory Neil Shapiro SM_VA_START(ap, msg);
4593299c2f1SGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
46012ed1c7cSGregory Neil Shapiro SM_VA_END(ap);
46112ed1c7cSGregory Neil Shapiro putoutmsg(MsgBuf, false, false);
462c2aa98e2SPeter Wemm
463c2aa98e2SPeter Wemm /* save this message for mailq printing */
464c2aa98e2SPeter Wemm switch (MsgBuf[0])
465c2aa98e2SPeter Wemm {
466c2aa98e2SPeter Wemm case '4':
467c2aa98e2SPeter Wemm case '8':
468c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL)
469c2aa98e2SPeter Wemm break;
4703299c2f1SGregory Neil Shapiro /* FALLTHROUGH */
471c2aa98e2SPeter Wemm
472c2aa98e2SPeter Wemm case '5':
47312ed1c7cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
474c0c4794dSGregory Neil Shapiro sm_free(CurEnv->e_message);
4756f9c8e5bSGregory Neil Shapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
476c2aa98e2SPeter Wemm break;
477c2aa98e2SPeter Wemm }
478c2aa98e2SPeter Wemm }
4796f9c8e5bSGregory Neil Shapiro
480da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
481da7d7b9cSGregory Neil Shapiro /*
482da7d7b9cSGregory Neil Shapiro ** EMESSAGE -- print message (not necessarily an error)
483da7d7b9cSGregory Neil Shapiro ** (same as message() but requires reply code and enhanced status code)
484da7d7b9cSGregory Neil Shapiro **
485da7d7b9cSGregory Neil Shapiro ** Parameters:
486da7d7b9cSGregory Neil Shapiro ** replycode -- SMTP reply code.
487da7d7b9cSGregory Neil Shapiro ** enhsc -- enhanced status code.
488da7d7b9cSGregory Neil Shapiro ** msg -- the message (sm_io_printf fmt) -- it can begin with
489da7d7b9cSGregory Neil Shapiro ** an SMTP reply code. If not, 050 is assumed.
490da7d7b9cSGregory Neil Shapiro ** (others) -- sm_io_printf arguments
491da7d7b9cSGregory Neil Shapiro **
492da7d7b9cSGregory Neil Shapiro ** Returns:
493da7d7b9cSGregory Neil Shapiro ** none
494da7d7b9cSGregory Neil Shapiro */
495da7d7b9cSGregory Neil Shapiro
496da7d7b9cSGregory Neil Shapiro /*VARARGS3*/
497da7d7b9cSGregory Neil Shapiro void
498da7d7b9cSGregory Neil Shapiro # ifdef __STDC__
emessage(const char * replycode,const char * enhsc,const char * msg,...)499da7d7b9cSGregory Neil Shapiro emessage(const char *replycode, const char *enhsc, const char *msg, ...)
500da7d7b9cSGregory Neil Shapiro # else /* __STDC__ */
501da7d7b9cSGregory Neil Shapiro emessage(replycode, enhsc, msg, va_alist)
502da7d7b9cSGregory Neil Shapiro const char *replycode;
503da7d7b9cSGregory Neil Shapiro const char *enhsc;
504da7d7b9cSGregory Neil Shapiro const char *msg;
505da7d7b9cSGregory Neil Shapiro va_dcl
506da7d7b9cSGregory Neil Shapiro # endif /* __STDC__ */
507da7d7b9cSGregory Neil Shapiro {
508da7d7b9cSGregory Neil Shapiro char *errtxt;
509da7d7b9cSGregory Neil Shapiro SM_VA_LOCAL_DECL
510da7d7b9cSGregory Neil Shapiro
511da7d7b9cSGregory Neil Shapiro errno = 0;
512da7d7b9cSGregory Neil Shapiro SM_VA_START(ap, msg);
513da7d7b9cSGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, replycode, enhsc, 0, msg, ap);
514da7d7b9cSGregory Neil Shapiro SM_VA_END(ap);
515da7d7b9cSGregory Neil Shapiro putoutmsg(MsgBuf, false, false);
516da7d7b9cSGregory Neil Shapiro
517da7d7b9cSGregory Neil Shapiro /* save this message for mailq printing */
518da7d7b9cSGregory Neil Shapiro switch (MsgBuf[0])
519da7d7b9cSGregory Neil Shapiro {
520da7d7b9cSGregory Neil Shapiro case '4':
521da7d7b9cSGregory Neil Shapiro case '8':
522da7d7b9cSGregory Neil Shapiro if (CurEnv->e_message != NULL)
523da7d7b9cSGregory Neil Shapiro break;
524da7d7b9cSGregory Neil Shapiro /* FALLTHROUGH */
525da7d7b9cSGregory Neil Shapiro
526da7d7b9cSGregory Neil Shapiro case '5':
527da7d7b9cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
528da7d7b9cSGregory Neil Shapiro sm_free(CurEnv->e_message);
529da7d7b9cSGregory Neil Shapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
530da7d7b9cSGregory Neil Shapiro break;
531da7d7b9cSGregory Neil Shapiro }
532da7d7b9cSGregory Neil Shapiro }
533da7d7b9cSGregory Neil Shapiro
534da7d7b9cSGregory Neil Shapiro /*
535da7d7b9cSGregory Neil Shapiro ** EXTSC -- check and extract a status codes
536da7d7b9cSGregory Neil Shapiro **
537da7d7b9cSGregory Neil Shapiro ** Parameters:
538da7d7b9cSGregory Neil Shapiro ** msg -- string with possible enhanced status code.
539da7d7b9cSGregory Neil Shapiro ** delim -- delim for enhanced status code.
540da7d7b9cSGregory Neil Shapiro ** replycode -- pointer to storage for SMTP reply code;
541da7d7b9cSGregory Neil Shapiro ** must be != NULL and have space for at least
542da7d7b9cSGregory Neil Shapiro ** 4 characters.
543da7d7b9cSGregory Neil Shapiro ** enhsc -- pointer to storage for enhanced status code;
544da7d7b9cSGregory Neil Shapiro ** must be != NULL and have space for at least
545da7d7b9cSGregory Neil Shapiro ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
546da7d7b9cSGregory Neil Shapiro **
547da7d7b9cSGregory Neil Shapiro ** Returns:
548da7d7b9cSGregory Neil Shapiro ** -1 -- no SMTP reply code.
549da7d7b9cSGregory Neil Shapiro ** >=3 -- offset of error text in msg.
550da7d7b9cSGregory Neil Shapiro ** (<=4 -- no enhanced status code)
551da7d7b9cSGregory Neil Shapiro */
552da7d7b9cSGregory Neil Shapiro
553da7d7b9cSGregory Neil Shapiro int
extsc(msg,delim,replycode,enhsc)554da7d7b9cSGregory Neil Shapiro extsc(msg, delim, replycode, enhsc)
555da7d7b9cSGregory Neil Shapiro const char *msg;
556da7d7b9cSGregory Neil Shapiro int delim;
557da7d7b9cSGregory Neil Shapiro char *replycode;
558da7d7b9cSGregory Neil Shapiro char *enhsc;
559da7d7b9cSGregory Neil Shapiro {
560da7d7b9cSGregory Neil Shapiro int offset;
561da7d7b9cSGregory Neil Shapiro
562da7d7b9cSGregory Neil Shapiro SM_REQUIRE(replycode != NULL);
563da7d7b9cSGregory Neil Shapiro SM_REQUIRE(enhsc != NULL);
564da7d7b9cSGregory Neil Shapiro replycode[0] = '\0';
565da7d7b9cSGregory Neil Shapiro enhsc[0] = '\0';
566da7d7b9cSGregory Neil Shapiro if (msg == NULL)
567da7d7b9cSGregory Neil Shapiro return -1;
568da7d7b9cSGregory Neil Shapiro if (!ISSMTPREPLY(msg))
569da7d7b9cSGregory Neil Shapiro return -1;
570da7d7b9cSGregory Neil Shapiro sm_strlcpy(replycode, msg, 4);
571da7d7b9cSGregory Neil Shapiro if (msg[3] == '\0')
572da7d7b9cSGregory Neil Shapiro return 3;
573da7d7b9cSGregory Neil Shapiro offset = 4;
574da7d7b9cSGregory Neil Shapiro if (isenhsc(msg + 4, delim))
575da7d7b9cSGregory Neil Shapiro offset = extenhsc(msg + 4, delim, enhsc) + 4;
576da7d7b9cSGregory Neil Shapiro return offset;
577da7d7b9cSGregory Neil Shapiro }
578da7d7b9cSGregory Neil Shapiro #endif /* _FFR_PROXY */
5796f9c8e5bSGregory Neil Shapiro
58012ed1c7cSGregory Neil Shapiro /*
581c2aa98e2SPeter Wemm ** NMESSAGE -- print message (not necessarily an error)
582c2aa98e2SPeter Wemm **
583c2aa98e2SPeter Wemm ** Just like "message" except it never puts the to... tag on.
584c2aa98e2SPeter Wemm **
585c2aa98e2SPeter Wemm ** Parameters:
58612ed1c7cSGregory Neil Shapiro ** msg -- the message (sm_io_printf fmt) -- if it begins
587c2aa98e2SPeter Wemm ** with a three digit SMTP reply code, that is used,
588c2aa98e2SPeter Wemm ** otherwise 050 is assumed.
58912ed1c7cSGregory Neil Shapiro ** (others) -- sm_io_printf arguments
590c2aa98e2SPeter Wemm **
591c2aa98e2SPeter Wemm ** Returns:
592c2aa98e2SPeter Wemm ** none
593c2aa98e2SPeter Wemm */
594c2aa98e2SPeter Wemm
595c2aa98e2SPeter Wemm /*VARARGS1*/
596c2aa98e2SPeter Wemm void
597c2aa98e2SPeter Wemm #ifdef __STDC__
nmessage(const char * msg,...)598c2aa98e2SPeter Wemm nmessage(const char *msg, ...)
5993299c2f1SGregory Neil Shapiro #else /* __STDC__ */
600c2aa98e2SPeter Wemm nmessage(msg, va_alist)
601c2aa98e2SPeter Wemm const char *msg;
602c2aa98e2SPeter Wemm va_dcl
6033299c2f1SGregory Neil Shapiro #endif /* __STDC__ */
604c2aa98e2SPeter Wemm {
6053299c2f1SGregory Neil Shapiro char *errtxt;
60612ed1c7cSGregory Neil Shapiro SM_VA_LOCAL_DECL
607c2aa98e2SPeter Wemm
608c2aa98e2SPeter Wemm errno = 0;
60912ed1c7cSGregory Neil Shapiro SM_VA_START(ap, msg);
6103299c2f1SGregory Neil Shapiro errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
6113299c2f1SGregory Neil Shapiro (char *) NULL, 0, msg, ap);
61212ed1c7cSGregory Neil Shapiro SM_VA_END(ap);
61312ed1c7cSGregory Neil Shapiro putoutmsg(MsgBuf, false, false);
614c2aa98e2SPeter Wemm
615c2aa98e2SPeter Wemm /* save this message for mailq printing */
616c2aa98e2SPeter Wemm switch (MsgBuf[0])
617c2aa98e2SPeter Wemm {
618c2aa98e2SPeter Wemm case '4':
619c2aa98e2SPeter Wemm case '8':
620c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL)
621c2aa98e2SPeter Wemm break;
6223299c2f1SGregory Neil Shapiro /* FALLTHROUGH */
623c2aa98e2SPeter Wemm
624c2aa98e2SPeter Wemm case '5':
62512ed1c7cSGregory Neil Shapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
626c0c4794dSGregory Neil Shapiro sm_free(CurEnv->e_message);
627951742c4SGregory Neil Shapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
628c2aa98e2SPeter Wemm break;
629c2aa98e2SPeter Wemm }
630c2aa98e2SPeter Wemm }
6315b0945b5SGregory Neil Shapiro
63212ed1c7cSGregory Neil Shapiro /*
633c2aa98e2SPeter Wemm ** PUTOUTMSG -- output error message to transcript and channel
634c2aa98e2SPeter Wemm **
635c2aa98e2SPeter Wemm ** Parameters:
636c2aa98e2SPeter Wemm ** msg -- message to output (in SMTP format).
63712ed1c7cSGregory Neil Shapiro ** holdmsg -- if true, don't output a copy of the message to
638c2aa98e2SPeter Wemm ** our output channel.
63912ed1c7cSGregory Neil Shapiro ** heldmsg -- if true, this is a previously held message;
640c2aa98e2SPeter Wemm ** don't log it to the transcript file.
641c2aa98e2SPeter Wemm **
642c2aa98e2SPeter Wemm ** Returns:
643c2aa98e2SPeter Wemm ** none.
644c2aa98e2SPeter Wemm **
645c2aa98e2SPeter Wemm ** Side Effects:
646c2aa98e2SPeter Wemm ** Outputs msg to the transcript.
647c2aa98e2SPeter Wemm ** If appropriate, outputs it to the channel.
648c2aa98e2SPeter Wemm ** Deletes SMTP reply code number as appropriate.
649c2aa98e2SPeter Wemm */
650c2aa98e2SPeter Wemm
6513299c2f1SGregory Neil Shapiro static void
putoutmsg(msg,holdmsg,heldmsg)652c2aa98e2SPeter Wemm putoutmsg(msg, holdmsg, heldmsg)
653c2aa98e2SPeter Wemm char *msg;
654c2aa98e2SPeter Wemm bool holdmsg;
655c2aa98e2SPeter Wemm bool heldmsg;
656c2aa98e2SPeter Wemm {
657c2aa98e2SPeter Wemm char msgcode = msg[0];
658951742c4SGregory Neil Shapiro char *errtxt = msg;
659951742c4SGregory Neil Shapiro char *id;
660c2aa98e2SPeter Wemm
661c2aa98e2SPeter Wemm /* display for debugging */
662c2aa98e2SPeter Wemm if (tTd(54, 8))
66312ed1c7cSGregory Neil Shapiro sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
664c2aa98e2SPeter Wemm heldmsg ? " (held)" : "");
665c2aa98e2SPeter Wemm
666c2aa98e2SPeter Wemm /* map warnings to something SMTP can handle */
667c2aa98e2SPeter Wemm if (msgcode == '6')
668c2aa98e2SPeter Wemm msg[0] = '5';
669c2aa98e2SPeter Wemm else if (msgcode == '8')
670c2aa98e2SPeter Wemm msg[0] = '4';
671951742c4SGregory Neil Shapiro id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
672c2aa98e2SPeter Wemm
673c2aa98e2SPeter Wemm /* output to transcript if serious */
674c2aa98e2SPeter Wemm if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
675c2aa98e2SPeter Wemm strchr("45", msg[0]) != NULL)
67612ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
67712ed1c7cSGregory Neil Shapiro msg);
678c2aa98e2SPeter Wemm
67912ed1c7cSGregory Neil Shapiro if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
680951742c4SGregory Neil Shapiro sm_syslog(LOG_INFO, id,
68112ed1c7cSGregory Neil Shapiro "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
68212ed1c7cSGregory Neil Shapiro heldmsg ? " (held)" : "");
683c2aa98e2SPeter Wemm
684c2aa98e2SPeter Wemm if (msgcode == '8')
685c2aa98e2SPeter Wemm msg[0] = '0';
686c2aa98e2SPeter Wemm
687c2aa98e2SPeter Wemm /* output to channel if appropriate */
688c2aa98e2SPeter Wemm if (!Verbose && msg[0] == '0')
689c2aa98e2SPeter Wemm return;
690c2aa98e2SPeter Wemm if (holdmsg)
691c2aa98e2SPeter Wemm {
692c2aa98e2SPeter Wemm /* save for possible future display */
693c2aa98e2SPeter Wemm msg[0] = msgcode;
6943299c2f1SGregory Neil Shapiro if (HeldMessageBuf[0] == '5' && msgcode == '4')
6953299c2f1SGregory Neil Shapiro return;
696951742c4SGregory Neil Shapiro (void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
697c2aa98e2SPeter Wemm return;
698c2aa98e2SPeter Wemm }
699c2aa98e2SPeter Wemm
70012ed1c7cSGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
701c2aa98e2SPeter Wemm
702c2aa98e2SPeter Wemm if (OutChannel == NULL)
703c2aa98e2SPeter Wemm return;
704c2aa98e2SPeter Wemm
7053299c2f1SGregory Neil Shapiro /* find actual text of error (after SMTP status codes) */
7063299c2f1SGregory Neil Shapiro if (ISSMTPREPLY(errtxt))
7073299c2f1SGregory Neil Shapiro {
7083299c2f1SGregory Neil Shapiro int l;
7093299c2f1SGregory Neil Shapiro
7103299c2f1SGregory Neil Shapiro errtxt += 4;
7113299c2f1SGregory Neil Shapiro l = isenhsc(errtxt, ' ');
7123299c2f1SGregory Neil Shapiro if (l <= 0)
7133299c2f1SGregory Neil Shapiro l = isenhsc(errtxt, '\0');
7143299c2f1SGregory Neil Shapiro if (l > 0)
7153299c2f1SGregory Neil Shapiro errtxt += l + 1;
7163299c2f1SGregory Neil Shapiro }
7173299c2f1SGregory Neil Shapiro
718c2aa98e2SPeter Wemm /* if DisConnected, OutChannel now points to the transcript */
719c2aa98e2SPeter Wemm if (!DisConnected &&
720c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
72112ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
72212ed1c7cSGregory Neil Shapiro msg);
723c2aa98e2SPeter Wemm else
72412ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
72512ed1c7cSGregory Neil Shapiro errtxt);
726c2aa98e2SPeter Wemm if (TrafficLogFile != NULL)
72712ed1c7cSGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
72812ed1c7cSGregory Neil Shapiro "%05d >>> %s\n", (int) CurrentPid,
72912ed1c7cSGregory Neil Shapiro (OpMode == MD_SMTP || OpMode == MD_DAEMON)
73012ed1c7cSGregory Neil Shapiro ? msg : errtxt);
73112ed1c7cSGregory Neil Shapiro #if !PIPELINING
732*2fb4f839SGregory Neil Shapiro /*
733*2fb4f839SGregory Neil Shapiro ** Note: in case of an SMTP reply this should check
734*2fb4f839SGregory Neil Shapiro ** that the last line of msg is not a continuation line
735*2fb4f839SGregory Neil Shapiro ** but that's probably not worth the effort.
736*2fb4f839SGregory Neil Shapiro */
737*2fb4f839SGregory Neil Shapiro
738*2fb4f839SGregory Neil Shapiro if (ISSMTPREPLY(msg))
73912ed1c7cSGregory Neil Shapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
74012ed1c7cSGregory Neil Shapiro if (!sm_io_error(OutChannel) || DisConnected)
741c2aa98e2SPeter Wemm return;
742c2aa98e2SPeter Wemm
743c2aa98e2SPeter Wemm /*
744c2aa98e2SPeter Wemm ** Error on output -- if reporting lost channel, just ignore it.
745c2aa98e2SPeter Wemm ** Also, ignore errors from QUIT response (221 message) -- some
746c2aa98e2SPeter Wemm ** rude servers don't read result.
747c2aa98e2SPeter Wemm */
748c2aa98e2SPeter Wemm
74912ed1c7cSGregory Neil Shapiro if (InChannel == NULL || sm_io_eof(InChannel) ||
75012ed1c7cSGregory Neil Shapiro sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
751c2aa98e2SPeter Wemm return;
752c2aa98e2SPeter Wemm
753c2aa98e2SPeter Wemm /* can't call syserr, 'cause we are using MsgBuf */
75412ed1c7cSGregory Neil Shapiro HoldErrs = true;
755c2aa98e2SPeter Wemm if (LogLevel > 0)
756951742c4SGregory Neil Shapiro sm_syslog(LOG_CRIT, id,
757c2aa98e2SPeter Wemm "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
75812ed1c7cSGregory Neil Shapiro CURHOSTNAME,
75912ed1c7cSGregory Neil Shapiro shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
76012ed1c7cSGregory Neil Shapiro #endif /* !PIPELINING */
761c2aa98e2SPeter Wemm }
7625b0945b5SGregory Neil Shapiro
76312ed1c7cSGregory Neil Shapiro /*
764c2aa98e2SPeter Wemm ** PUTERRMSG -- like putoutmsg, but does special processing for error messages
765c2aa98e2SPeter Wemm **
766c2aa98e2SPeter Wemm ** Parameters:
767c2aa98e2SPeter Wemm ** msg -- the message to output.
768c2aa98e2SPeter Wemm **
769c2aa98e2SPeter Wemm ** Returns:
770c2aa98e2SPeter Wemm ** none.
771c2aa98e2SPeter Wemm **
772c2aa98e2SPeter Wemm ** Side Effects:
773c2aa98e2SPeter Wemm ** Sets the fatal error bit in the envelope as appropriate.
774c2aa98e2SPeter Wemm */
775c2aa98e2SPeter Wemm
7763299c2f1SGregory Neil Shapiro static void
puterrmsg(msg)777c2aa98e2SPeter Wemm puterrmsg(msg)
778c2aa98e2SPeter Wemm char *msg;
779c2aa98e2SPeter Wemm {
780c2aa98e2SPeter Wemm char msgcode = msg[0];
781c2aa98e2SPeter Wemm
782c2aa98e2SPeter Wemm /* output the message as usual */
78312ed1c7cSGregory Neil Shapiro putoutmsg(msg, HoldErrs, false);
784c2aa98e2SPeter Wemm
785c2aa98e2SPeter Wemm /* be careful about multiple error messages */
786c2aa98e2SPeter Wemm if (OnlyOneError)
78712ed1c7cSGregory Neil Shapiro HoldErrs = true;
788c2aa98e2SPeter Wemm
789c2aa98e2SPeter Wemm /* signal the error */
790c2aa98e2SPeter Wemm Errors++;
791c2aa98e2SPeter Wemm
792c2aa98e2SPeter Wemm if (CurEnv == NULL)
793c2aa98e2SPeter Wemm return;
794c2aa98e2SPeter Wemm
795c2aa98e2SPeter Wemm if (msgcode == '6')
796c2aa98e2SPeter Wemm {
797c2aa98e2SPeter Wemm /* notify the postmaster */
798c2aa98e2SPeter Wemm CurEnv->e_flags |= EF_PM_NOTIFY;
799c2aa98e2SPeter Wemm }
800c2aa98e2SPeter Wemm else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
801c2aa98e2SPeter Wemm {
802c2aa98e2SPeter Wemm /* mark long-term fatal errors */
803c2aa98e2SPeter Wemm CurEnv->e_flags |= EF_FATALERRS;
804c2aa98e2SPeter Wemm }
805c2aa98e2SPeter Wemm }
8065b0945b5SGregory Neil Shapiro
80712ed1c7cSGregory Neil Shapiro /*
8083299c2f1SGregory Neil Shapiro ** ISENHSC -- check whether a string contains an enhanced status code
8093299c2f1SGregory Neil Shapiro **
8103299c2f1SGregory Neil Shapiro ** Parameters:
8113299c2f1SGregory Neil Shapiro ** s -- string with possible enhanced status code.
8123299c2f1SGregory Neil Shapiro ** delim -- delim for enhanced status code.
8133299c2f1SGregory Neil Shapiro **
8143299c2f1SGregory Neil Shapiro ** Returns:
8153299c2f1SGregory Neil Shapiro ** 0 -- no enhanced status code.
8163299c2f1SGregory Neil Shapiro ** >4 -- length of enhanced status code.
8173299c2f1SGregory Neil Shapiro */
8185b0945b5SGregory Neil Shapiro
8193299c2f1SGregory Neil Shapiro int
isenhsc(s,delim)8203299c2f1SGregory Neil Shapiro isenhsc(s, delim)
8213299c2f1SGregory Neil Shapiro const char *s;
8223299c2f1SGregory Neil Shapiro int delim;
8233299c2f1SGregory Neil Shapiro {
8243299c2f1SGregory Neil Shapiro int l, h;
8253299c2f1SGregory Neil Shapiro
8263299c2f1SGregory Neil Shapiro if (s == NULL)
8273299c2f1SGregory Neil Shapiro return 0;
8283299c2f1SGregory Neil Shapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8293299c2f1SGregory Neil Shapiro return 0;
8303299c2f1SGregory Neil Shapiro h = 0;
8313299c2f1SGregory Neil Shapiro l = 2;
8323299c2f1SGregory Neil Shapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8333299c2f1SGregory Neil Shapiro ++h;
8343299c2f1SGregory Neil Shapiro if (h == 0 || s[l + h] != '.')
8353299c2f1SGregory Neil Shapiro return 0;
8363299c2f1SGregory Neil Shapiro l += h + 1;
8373299c2f1SGregory Neil Shapiro h = 0;
8383299c2f1SGregory Neil Shapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8393299c2f1SGregory Neil Shapiro ++h;
8403299c2f1SGregory Neil Shapiro if (h == 0 || s[l + h] != delim)
8413299c2f1SGregory Neil Shapiro return 0;
8423299c2f1SGregory Neil Shapiro return l + h;
8433299c2f1SGregory Neil Shapiro }
8445b0945b5SGregory Neil Shapiro
84512ed1c7cSGregory Neil Shapiro /*
8463299c2f1SGregory Neil Shapiro ** EXTENHSC -- check and extract an enhanced status code
8473299c2f1SGregory Neil Shapiro **
8483299c2f1SGregory Neil Shapiro ** Parameters:
8493299c2f1SGregory Neil Shapiro ** s -- string with possible enhanced status code.
8503299c2f1SGregory Neil Shapiro ** delim -- delim for enhanced status code.
8513299c2f1SGregory Neil Shapiro ** e -- pointer to storage for enhanced status code.
8523299c2f1SGregory Neil Shapiro ** must be != NULL and have space for at least
8533299c2f1SGregory Neil Shapiro ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
8543299c2f1SGregory Neil Shapiro **
8553299c2f1SGregory Neil Shapiro ** Returns:
8563299c2f1SGregory Neil Shapiro ** 0 -- no enhanced status code.
8573299c2f1SGregory Neil Shapiro ** >4 -- length of enhanced status code.
8583299c2f1SGregory Neil Shapiro **
8593299c2f1SGregory Neil Shapiro ** Side Effects:
8603299c2f1SGregory Neil Shapiro ** fills e with enhanced status code.
8613299c2f1SGregory Neil Shapiro */
86212ed1c7cSGregory Neil Shapiro
8633299c2f1SGregory Neil Shapiro int
extenhsc(s,delim,e)8643299c2f1SGregory Neil Shapiro extenhsc(s, delim, e)
8653299c2f1SGregory Neil Shapiro const char *s;
8663299c2f1SGregory Neil Shapiro int delim;
8673299c2f1SGregory Neil Shapiro char *e;
8683299c2f1SGregory Neil Shapiro {
8693299c2f1SGregory Neil Shapiro int l, h;
8703299c2f1SGregory Neil Shapiro
8713299c2f1SGregory Neil Shapiro if (s == NULL)
8723299c2f1SGregory Neil Shapiro return 0;
8733299c2f1SGregory Neil Shapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
8743299c2f1SGregory Neil Shapiro return 0;
8753299c2f1SGregory Neil Shapiro h = 0;
8763299c2f1SGregory Neil Shapiro l = 2;
8773299c2f1SGregory Neil Shapiro e[0] = s[0];
8783299c2f1SGregory Neil Shapiro e[1] = '.';
8793299c2f1SGregory Neil Shapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8803299c2f1SGregory Neil Shapiro {
8813299c2f1SGregory Neil Shapiro e[l + h] = s[l + h];
8823299c2f1SGregory Neil Shapiro ++h;
8833299c2f1SGregory Neil Shapiro }
8843299c2f1SGregory Neil Shapiro if (h == 0 || s[l + h] != '.')
8853299c2f1SGregory Neil Shapiro return 0;
8863299c2f1SGregory Neil Shapiro e[l + h] = '.';
8873299c2f1SGregory Neil Shapiro l += h + 1;
8883299c2f1SGregory Neil Shapiro h = 0;
8893299c2f1SGregory Neil Shapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
8903299c2f1SGregory Neil Shapiro {
8913299c2f1SGregory Neil Shapiro e[l + h] = s[l + h];
8923299c2f1SGregory Neil Shapiro ++h;
8933299c2f1SGregory Neil Shapiro }
8943299c2f1SGregory Neil Shapiro if (h == 0 || s[l + h] != delim)
8953299c2f1SGregory Neil Shapiro return 0;
8963299c2f1SGregory Neil Shapiro e[l + h] = '\0';
8973299c2f1SGregory Neil Shapiro return l + h;
8983299c2f1SGregory Neil Shapiro }
8995b0945b5SGregory Neil Shapiro
900*2fb4f839SGregory Neil Shapiro #if USE_EAI
901*2fb4f839SGregory Neil Shapiro /*
902*2fb4f839SGregory Neil Shapiro ** SKIPADDRHOST -- skip address and host in a message
903*2fb4f839SGregory Neil Shapiro **
904*2fb4f839SGregory Neil Shapiro ** Parameters:
905*2fb4f839SGregory Neil Shapiro ** s -- string with possible address and host
906*2fb4f839SGregory Neil Shapiro ** skiphost -- skip also host?
907*2fb4f839SGregory Neil Shapiro **
908*2fb4f839SGregory Neil Shapiro ** Returns:
909*2fb4f839SGregory Neil Shapiro ** 0 -- no address and host
910*2fb4f839SGregory Neil Shapiro ** >0 -- position after address (and host)
911*2fb4f839SGregory Neil Shapiro */
912*2fb4f839SGregory Neil Shapiro
913*2fb4f839SGregory Neil Shapiro int
skipaddrhost(s,skiphost)914*2fb4f839SGregory Neil Shapiro skipaddrhost(s, skiphost)
915*2fb4f839SGregory Neil Shapiro const char *s;
916*2fb4f839SGregory Neil Shapiro bool skiphost;
917*2fb4f839SGregory Neil Shapiro {
918*2fb4f839SGregory Neil Shapiro char *str;
919*2fb4f839SGregory Neil Shapiro size_t len;
920*2fb4f839SGregory Neil Shapiro
921*2fb4f839SGregory Neil Shapiro #define SM_ADDR_DELIM "... "
922*2fb4f839SGregory Neil Shapiro if (s == NULL)
923*2fb4f839SGregory Neil Shapiro return 0;
924*2fb4f839SGregory Neil Shapiro str = strstr(s, SM_ADDR_DELIM);
925*2fb4f839SGregory Neil Shapiro if (str == NULL)
926*2fb4f839SGregory Neil Shapiro return 0;
927*2fb4f839SGregory Neil Shapiro str += sizeof(SM_ADDR_DELIM) + 1;
928*2fb4f839SGregory Neil Shapiro len = strlen(s);
929*2fb4f839SGregory Neil Shapiro if (str >= s + len)
930*2fb4f839SGregory Neil Shapiro return 0;
931*2fb4f839SGregory Neil Shapiro if (!skiphost)
932*2fb4f839SGregory Neil Shapiro return str - s + 1;
933*2fb4f839SGregory Neil Shapiro
934*2fb4f839SGregory Neil Shapiro str = strchr(str, ' ');
935*2fb4f839SGregory Neil Shapiro if (str >= s + len)
936*2fb4f839SGregory Neil Shapiro return 0;
937*2fb4f839SGregory Neil Shapiro return str - s + 1;
938*2fb4f839SGregory Neil Shapiro }
939*2fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
940*2fb4f839SGregory Neil Shapiro
94112ed1c7cSGregory Neil Shapiro /*
942c2aa98e2SPeter Wemm ** FMTMSG -- format a message into buffer.
943c2aa98e2SPeter Wemm **
944c2aa98e2SPeter Wemm ** Parameters:
9453299c2f1SGregory Neil Shapiro ** eb -- error buffer to get result -- MUST BE MsgBuf.
946c2aa98e2SPeter Wemm ** to -- the recipient tag for this message.
9473299c2f1SGregory Neil Shapiro ** num -- default three digit SMTP reply code.
9483299c2f1SGregory Neil Shapiro ** enhsc -- enhanced status code.
949c2aa98e2SPeter Wemm ** en -- the error number to display.
9505b0945b5SGregory Neil Shapiro ** fmt -- format of string: See NOTE below.
9513299c2f1SGregory Neil Shapiro ** ap -- arguments for fmt.
952c2aa98e2SPeter Wemm **
953c2aa98e2SPeter Wemm ** Returns:
9543299c2f1SGregory Neil Shapiro ** pointer to error text beyond status codes.
955c2aa98e2SPeter Wemm **
9565b0945b5SGregory Neil Shapiro ** NOTE:
9575b0945b5SGregory Neil Shapiro ** Do NOT use "%s" as fmt if the argument starts with an SMTP
9585b0945b5SGregory Neil Shapiro ** reply code!
959c2aa98e2SPeter Wemm */
960c2aa98e2SPeter Wemm
9613299c2f1SGregory Neil Shapiro static char *
fmtmsg(eb,to,num,enhsc,eno,fmt,ap)9623299c2f1SGregory Neil Shapiro fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
963c2aa98e2SPeter Wemm register char *eb;
964c2aa98e2SPeter Wemm const char *to;
965c2aa98e2SPeter Wemm const char *num;
9663299c2f1SGregory Neil Shapiro const char *enhsc;
967c2aa98e2SPeter Wemm int eno;
968c2aa98e2SPeter Wemm const char *fmt;
969*2fb4f839SGregory Neil Shapiro va_list ap;
970c2aa98e2SPeter Wemm {
971c2aa98e2SPeter Wemm char del;
972c2aa98e2SPeter Wemm int l;
973951742c4SGregory Neil Shapiro int spaceleft = sizeof(MsgBuf);
9743299c2f1SGregory Neil Shapiro char *errtxt;
975c2aa98e2SPeter Wemm
976c2aa98e2SPeter Wemm /* output the reply code */
9773299c2f1SGregory Neil Shapiro if (ISSMTPCODE(fmt))
978c2aa98e2SPeter Wemm {
979c2aa98e2SPeter Wemm num = fmt;
980c2aa98e2SPeter Wemm fmt += 4;
981c2aa98e2SPeter Wemm }
982c2aa98e2SPeter Wemm if (num[3] == '-')
983c2aa98e2SPeter Wemm del = '-';
984c2aa98e2SPeter Wemm else
985c2aa98e2SPeter Wemm del = ' ';
98612ed1c7cSGregory Neil Shapiro if (SoftBounce && num[0] == '5')
98712ed1c7cSGregory Neil Shapiro {
98812ed1c7cSGregory Neil Shapiro /* replace 5 by 4 */
98912ed1c7cSGregory Neil Shapiro (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
99012ed1c7cSGregory Neil Shapiro }
99112ed1c7cSGregory Neil Shapiro else
99212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
993c2aa98e2SPeter Wemm eb += 4;
994c2aa98e2SPeter Wemm spaceleft -= 4;
995c2aa98e2SPeter Wemm
9963299c2f1SGregory Neil Shapiro if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
9973299c2f1SGregory Neil Shapiro {
9983299c2f1SGregory Neil Shapiro /* copy enh.status code including trailing blank */
9993299c2f1SGregory Neil Shapiro l++;
100012ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(eb, fmt, l + 1);
10013299c2f1SGregory Neil Shapiro eb += l;
10023299c2f1SGregory Neil Shapiro spaceleft -= l;
10033299c2f1SGregory Neil Shapiro fmt += l;
10043299c2f1SGregory Neil Shapiro }
10053299c2f1SGregory Neil Shapiro else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
10063299c2f1SGregory Neil Shapiro {
10073299c2f1SGregory Neil Shapiro /* copy enh.status code */
100812ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(eb, enhsc, l + 1);
10093299c2f1SGregory Neil Shapiro eb[l] = ' ';
10103299c2f1SGregory Neil Shapiro eb[++l] = '\0';
10113299c2f1SGregory Neil Shapiro eb += l;
10123299c2f1SGregory Neil Shapiro spaceleft -= l;
10133299c2f1SGregory Neil Shapiro }
101412ed1c7cSGregory Neil Shapiro if (SoftBounce && eb[-l] == '5')
101512ed1c7cSGregory Neil Shapiro {
101612ed1c7cSGregory Neil Shapiro /* replace 5 by 4 */
101712ed1c7cSGregory Neil Shapiro eb[-l] = '4';
101812ed1c7cSGregory Neil Shapiro }
10193299c2f1SGregory Neil Shapiro errtxt = eb;
10203299c2f1SGregory Neil Shapiro
1021c2aa98e2SPeter Wemm /* output the file name and line number */
1022c2aa98e2SPeter Wemm if (FileName != NULL)
1023c2aa98e2SPeter Wemm {
102412ed1c7cSGregory Neil Shapiro (void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
1025c2aa98e2SPeter Wemm shortenstring(FileName, 83), LineNumber);
1026c2aa98e2SPeter Wemm eb += (l = strlen(eb));
1027c2aa98e2SPeter Wemm spaceleft -= l;
1028c2aa98e2SPeter Wemm }
1029c2aa98e2SPeter Wemm
103056477e1eSGregory Neil Shapiro /*
103156477e1eSGregory Neil Shapiro ** output the "to" address only if it is defined and one of the
103256477e1eSGregory Neil Shapiro ** following codes is used:
103356477e1eSGregory Neil Shapiro ** 050 internal notices, e.g., alias expansion
103456477e1eSGregory Neil Shapiro ** 250 Ok
103556477e1eSGregory Neil Shapiro ** 252 Cannot VRFY user, but will accept message and attempt delivery
103656477e1eSGregory Neil Shapiro ** 450 Requested mail action not taken: mailbox unavailable
103756477e1eSGregory Neil Shapiro ** 550 Requested action not taken: mailbox unavailable
103856477e1eSGregory Neil Shapiro ** 553 Requested action not taken: mailbox name not allowed
103956477e1eSGregory Neil Shapiro **
104056477e1eSGregory Neil Shapiro ** Notice: this still isn't "the right thing", this code shouldn't
104156477e1eSGregory Neil Shapiro ** (indirectly) depend on CurEnv->e_to.
104256477e1eSGregory Neil Shapiro */
104356477e1eSGregory Neil Shapiro
1044c2aa98e2SPeter Wemm if (to != NULL && to[0] != '\0' &&
104556477e1eSGregory Neil Shapiro (strncmp(num, "050", 3) == 0 ||
104656477e1eSGregory Neil Shapiro strncmp(num, "250", 3) == 0 ||
104756477e1eSGregory Neil Shapiro strncmp(num, "252", 3) == 0 ||
104856477e1eSGregory Neil Shapiro strncmp(num, "450", 3) == 0 ||
104956477e1eSGregory Neil Shapiro strncmp(num, "550", 3) == 0 ||
105056477e1eSGregory Neil Shapiro strncmp(num, "553", 3) == 0))
1051c2aa98e2SPeter Wemm {
1052*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
1053*2fb4f839SGregory Neil Shapiro char xbuf[MAXNAME + 1]; /* EAI:ok */
1054*2fb4f839SGregory Neil Shapiro int len;
1055*2fb4f839SGregory Neil Shapiro
1056*2fb4f839SGregory Neil Shapiro len = sizeof(xbuf);
1057*2fb4f839SGregory Neil Shapiro (void) sm_strlcpy(xbuf, to, len);
1058*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(xbuf, xbuf, len);
1059*2fb4f839SGregory Neil Shapiro (void) sm_strlcpyn(eb, spaceleft, 2,
1060*2fb4f839SGregory Neil Shapiro shortenstring(xbuf, MAXSHORTSTR), "... ");
1061*2fb4f839SGregory Neil Shapiro eb += strlen(eb);
1062*2fb4f839SGregory Neil Shapiro #else /* _FFR_8BITENVADDR */
106312ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(eb, spaceleft, 2,
106412ed1c7cSGregory Neil Shapiro shortenstring(to, MAXSHORTSTR), "... ");
1065c2aa98e2SPeter Wemm while (*eb != '\0')
1066c2aa98e2SPeter Wemm *eb++ &= 0177;
1067*2fb4f839SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */
1068*2fb4f839SGregory Neil Shapiro spaceleft -= strlen(eb);
1069c2aa98e2SPeter Wemm }
1070c2aa98e2SPeter Wemm
1071c2aa98e2SPeter Wemm /* output the message */
107212ed1c7cSGregory Neil Shapiro (void) sm_vsnprintf(eb, spaceleft, fmt, ap);
1073c2aa98e2SPeter Wemm spaceleft -= strlen(eb);
1074*2fb4f839SGregory Neil Shapiro #if USE_EAI
10755b0945b5SGregory Neil Shapiro eb += strlen(eb);
10765b0945b5SGregory Neil Shapiro #else
1077c2aa98e2SPeter Wemm while (*eb != '\0')
1078c2aa98e2SPeter Wemm *eb++ &= 0177;
10795b0945b5SGregory Neil Shapiro #endif
1080c2aa98e2SPeter Wemm
1081c2aa98e2SPeter Wemm /* output the error code, if any */
1082c2aa98e2SPeter Wemm if (eno != 0)
108312ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
10843299c2f1SGregory Neil Shapiro
10853299c2f1SGregory Neil Shapiro return errtxt;
1086c2aa98e2SPeter Wemm }
10875b0945b5SGregory Neil Shapiro
108812ed1c7cSGregory Neil Shapiro /*
1089c2aa98e2SPeter Wemm ** BUFFER_ERRORS -- arrange to buffer future error messages
1090c2aa98e2SPeter Wemm **
1091c2aa98e2SPeter Wemm ** Parameters:
1092c2aa98e2SPeter Wemm ** none
1093c2aa98e2SPeter Wemm **
1094c2aa98e2SPeter Wemm ** Returns:
1095c2aa98e2SPeter Wemm ** none.
1096c2aa98e2SPeter Wemm */
1097c2aa98e2SPeter Wemm
1098c2aa98e2SPeter Wemm void
buffer_errors()1099c2aa98e2SPeter Wemm buffer_errors()
1100c2aa98e2SPeter Wemm {
1101c2aa98e2SPeter Wemm HeldMessageBuf[0] = '\0';
110212ed1c7cSGregory Neil Shapiro HoldErrs = true;
1103c2aa98e2SPeter Wemm }
11045b0945b5SGregory Neil Shapiro
110512ed1c7cSGregory Neil Shapiro /*
1106c2aa98e2SPeter Wemm ** FLUSH_ERRORS -- flush the held error message buffer
1107c2aa98e2SPeter Wemm **
1108c2aa98e2SPeter Wemm ** Parameters:
1109c2aa98e2SPeter Wemm ** print -- if set, print the message, otherwise just
1110c2aa98e2SPeter Wemm ** delete it.
1111c2aa98e2SPeter Wemm **
1112c2aa98e2SPeter Wemm ** Returns:
1113c2aa98e2SPeter Wemm ** none.
1114c2aa98e2SPeter Wemm */
1115c2aa98e2SPeter Wemm
1116c2aa98e2SPeter Wemm void
flush_errors(print)1117c2aa98e2SPeter Wemm flush_errors(print)
1118c2aa98e2SPeter Wemm bool print;
1119c2aa98e2SPeter Wemm {
1120c2aa98e2SPeter Wemm if (print && HeldMessageBuf[0] != '\0')
112112ed1c7cSGregory Neil Shapiro putoutmsg(HeldMessageBuf, false, true);
1122c2aa98e2SPeter Wemm HeldMessageBuf[0] = '\0';
112312ed1c7cSGregory Neil Shapiro HoldErrs = false;
1124c2aa98e2SPeter Wemm }
112512ed1c7cSGregory Neil Shapiro /*
112612ed1c7cSGregory Neil Shapiro ** SM_ERRSTRING -- return string description of error code
1127c2aa98e2SPeter Wemm **
1128c2aa98e2SPeter Wemm ** Parameters:
1129c2aa98e2SPeter Wemm ** errnum -- the error number to translate
1130c2aa98e2SPeter Wemm **
1131c2aa98e2SPeter Wemm ** Returns:
1132c2aa98e2SPeter Wemm ** A string description of errnum.
1133c2aa98e2SPeter Wemm */
1134c2aa98e2SPeter Wemm
1135c2aa98e2SPeter Wemm const char *
sm_errstring(errnum)113612ed1c7cSGregory Neil Shapiro sm_errstring(errnum)
1137c2aa98e2SPeter Wemm int errnum;
1138c2aa98e2SPeter Wemm {
1139c2aa98e2SPeter Wemm char *dnsmsg;
1140c2aa98e2SPeter Wemm char *bp;
1141c2aa98e2SPeter Wemm static char buf[MAXLINE];
114212ed1c7cSGregory Neil Shapiro #if HASSTRERROR
114312ed1c7cSGregory Neil Shapiro char *err;
114412ed1c7cSGregory Neil Shapiro char errbuf[30];
11455b0945b5SGregory Neil Shapiro #endif
1146c2aa98e2SPeter Wemm #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
1147c2aa98e2SPeter Wemm extern char *sys_errlist[];
1148c2aa98e2SPeter Wemm extern int sys_nerr;
11495b0945b5SGregory Neil Shapiro #endif
1150c2aa98e2SPeter Wemm
1151c2aa98e2SPeter Wemm /*
1152c2aa98e2SPeter Wemm ** Handle special network error codes.
1153c2aa98e2SPeter Wemm **
1154c2aa98e2SPeter Wemm ** These are 4.2/4.3bsd specific; they should be in daemon.c.
1155c2aa98e2SPeter Wemm */
1156c2aa98e2SPeter Wemm
1157c2aa98e2SPeter Wemm dnsmsg = NULL;
1158c2aa98e2SPeter Wemm switch (errnum)
1159c2aa98e2SPeter Wemm {
1160c2aa98e2SPeter Wemm case ETIMEDOUT:
1161c2aa98e2SPeter Wemm case ECONNRESET:
1162c2aa98e2SPeter Wemm bp = buf;
1163c2aa98e2SPeter Wemm #if HASSTRERROR
116412ed1c7cSGregory Neil Shapiro err = strerror(errnum);
116512ed1c7cSGregory Neil Shapiro if (err == NULL)
116612ed1c7cSGregory Neil Shapiro {
1167951742c4SGregory Neil Shapiro (void) sm_snprintf(errbuf, sizeof(errbuf),
116812ed1c7cSGregory Neil Shapiro "Error %d", errnum);
116912ed1c7cSGregory Neil Shapiro err = errbuf;
117012ed1c7cSGregory Neil Shapiro }
117112ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
11723299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1173c2aa98e2SPeter Wemm if (errnum >= 0 && errnum < sys_nerr)
117412ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(bp, sys_errlist[errnum],
117512ed1c7cSGregory Neil Shapiro SPACELEFT(buf, bp));
1176c2aa98e2SPeter Wemm else
117712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
117812ed1c7cSGregory Neil Shapiro "Error %d", errnum);
11793299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1180c2aa98e2SPeter Wemm bp += strlen(bp);
1181c2aa98e2SPeter Wemm if (CurHostName != NULL)
1182c2aa98e2SPeter Wemm {
1183c2aa98e2SPeter Wemm if (errnum == ETIMEDOUT)
1184c2aa98e2SPeter Wemm {
118512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
118612ed1c7cSGregory Neil Shapiro " with ");
1187c2aa98e2SPeter Wemm bp += strlen(bp);
1188c2aa98e2SPeter Wemm }
1189c2aa98e2SPeter Wemm else
1190c2aa98e2SPeter Wemm {
1191c2aa98e2SPeter Wemm bp = buf;
119212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1193c2aa98e2SPeter Wemm "Connection reset by ");
1194c2aa98e2SPeter Wemm bp += strlen(bp);
1195c2aa98e2SPeter Wemm }
119612ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(bp,
119712ed1c7cSGregory Neil Shapiro shortenstring(CurHostName, MAXSHORTSTR),
119812ed1c7cSGregory Neil Shapiro SPACELEFT(buf, bp));
1199c2aa98e2SPeter Wemm bp += strlen(buf);
1200c2aa98e2SPeter Wemm }
1201c2aa98e2SPeter Wemm if (SmtpPhase != NULL)
1202c2aa98e2SPeter Wemm {
120312ed1c7cSGregory Neil Shapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp),
120412ed1c7cSGregory Neil Shapiro " during %s", SmtpPhase);
1205c2aa98e2SPeter Wemm }
12063299c2f1SGregory Neil Shapiro return buf;
1207c2aa98e2SPeter Wemm
1208c2aa98e2SPeter Wemm case EHOSTDOWN:
1209c2aa98e2SPeter Wemm if (CurHostName == NULL)
1210c2aa98e2SPeter Wemm break;
1211951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
1212c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR));
12133299c2f1SGregory Neil Shapiro return buf;
1214c2aa98e2SPeter Wemm
1215c2aa98e2SPeter Wemm case ECONNREFUSED:
1216c2aa98e2SPeter Wemm if (CurHostName == NULL)
1217c2aa98e2SPeter Wemm break;
1218951742c4SGregory Neil Shapiro (void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
1219c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR));
12203299c2f1SGregory Neil Shapiro return buf;
1221c2aa98e2SPeter Wemm
1222c2aa98e2SPeter Wemm #if NAMED_BIND
1223c2aa98e2SPeter Wemm case HOST_NOT_FOUND + E_DNSBASE:
1224c2aa98e2SPeter Wemm dnsmsg = "host not found";
1225c2aa98e2SPeter Wemm break;
1226c2aa98e2SPeter Wemm
1227c2aa98e2SPeter Wemm case TRY_AGAIN + E_DNSBASE:
1228c2aa98e2SPeter Wemm dnsmsg = "host name lookup failure";
1229c2aa98e2SPeter Wemm break;
1230c2aa98e2SPeter Wemm
1231c2aa98e2SPeter Wemm case NO_RECOVERY + E_DNSBASE:
1232c2aa98e2SPeter Wemm dnsmsg = "non-recoverable error";
1233c2aa98e2SPeter Wemm break;
1234c2aa98e2SPeter Wemm
1235c2aa98e2SPeter Wemm case NO_DATA + E_DNSBASE:
1236c2aa98e2SPeter Wemm dnsmsg = "no data known";
1237c2aa98e2SPeter Wemm break;
12383299c2f1SGregory Neil Shapiro #endif /* NAMED_BIND */
1239c2aa98e2SPeter Wemm
1240c2aa98e2SPeter Wemm case EPERM:
1241c2aa98e2SPeter Wemm /* SunOS gives "Not owner" -- this is the POSIX message */
1242c2aa98e2SPeter Wemm return "Operation not permitted";
1243c2aa98e2SPeter Wemm
1244c2aa98e2SPeter Wemm /*
1245c2aa98e2SPeter Wemm ** Error messages used internally in sendmail.
1246c2aa98e2SPeter Wemm */
1247c2aa98e2SPeter Wemm
1248c2aa98e2SPeter Wemm case E_SM_OPENTIMEOUT:
1249c2aa98e2SPeter Wemm return "Timeout on file open";
1250c2aa98e2SPeter Wemm
1251c2aa98e2SPeter Wemm case E_SM_NOSLINK:
1252c2aa98e2SPeter Wemm return "Symbolic links not allowed";
1253c2aa98e2SPeter Wemm
1254c2aa98e2SPeter Wemm case E_SM_NOHLINK:
1255c2aa98e2SPeter Wemm return "Hard links not allowed";
1256c2aa98e2SPeter Wemm
1257c2aa98e2SPeter Wemm case E_SM_REGONLY:
1258c2aa98e2SPeter Wemm return "Regular files only";
1259c2aa98e2SPeter Wemm
1260c2aa98e2SPeter Wemm case E_SM_ISEXEC:
1261c2aa98e2SPeter Wemm return "Executable files not allowed";
1262c2aa98e2SPeter Wemm
1263c2aa98e2SPeter Wemm case E_SM_WWDIR:
1264c2aa98e2SPeter Wemm return "World writable directory";
1265c2aa98e2SPeter Wemm
1266c2aa98e2SPeter Wemm case E_SM_GWDIR:
1267c2aa98e2SPeter Wemm return "Group writable directory";
1268c2aa98e2SPeter Wemm
1269c2aa98e2SPeter Wemm case E_SM_FILECHANGE:
1270c2aa98e2SPeter Wemm return "File changed after open";
1271c2aa98e2SPeter Wemm
1272c2aa98e2SPeter Wemm case E_SM_WWFILE:
1273c2aa98e2SPeter Wemm return "World writable file";
1274c2aa98e2SPeter Wemm
1275c2aa98e2SPeter Wemm case E_SM_GWFILE:
1276c2aa98e2SPeter Wemm return "Group writable file";
12773299c2f1SGregory Neil Shapiro
12783299c2f1SGregory Neil Shapiro case E_SM_GRFILE:
12793299c2f1SGregory Neil Shapiro return "Group readable file";
12803299c2f1SGregory Neil Shapiro
12813299c2f1SGregory Neil Shapiro case E_SM_WRFILE:
12823299c2f1SGregory Neil Shapiro return "World readable file";
1283c2aa98e2SPeter Wemm }
1284c2aa98e2SPeter Wemm
1285c2aa98e2SPeter Wemm if (dnsmsg != NULL)
1286c2aa98e2SPeter Wemm {
1287c2aa98e2SPeter Wemm bp = buf;
1288951742c4SGregory Neil Shapiro bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
1289c2aa98e2SPeter Wemm if (CurHostName != NULL)
1290c2aa98e2SPeter Wemm {
129112ed1c7cSGregory Neil Shapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
129212ed1c7cSGregory Neil Shapiro shortenstring(CurHostName, MAXSHORTSTR), ": ");
1293c2aa98e2SPeter Wemm bp += strlen(bp);
1294c2aa98e2SPeter Wemm }
129512ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1296c2aa98e2SPeter Wemm return buf;
1297c2aa98e2SPeter Wemm }
1298c2aa98e2SPeter Wemm
129912ed1c7cSGregory Neil Shapiro #if LDAPMAP
1300da7d7b9cSGregory Neil Shapiro if (errnum >= E_LDAPBASE - E_LDAP_SHIM)
13013299c2f1SGregory Neil Shapiro return ldap_err2string(errnum - E_LDAPBASE);
13025b0945b5SGregory Neil Shapiro #endif
13033299c2f1SGregory Neil Shapiro
1304c2aa98e2SPeter Wemm #if HASSTRERROR
130512ed1c7cSGregory Neil Shapiro err = strerror(errnum);
130612ed1c7cSGregory Neil Shapiro if (err == NULL)
130712ed1c7cSGregory Neil Shapiro {
1308951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
130912ed1c7cSGregory Neil Shapiro return buf;
131012ed1c7cSGregory Neil Shapiro }
131112ed1c7cSGregory Neil Shapiro return err;
13123299c2f1SGregory Neil Shapiro #else /* HASSTRERROR */
1313c2aa98e2SPeter Wemm if (errnum > 0 && errnum < sys_nerr)
13143299c2f1SGregory Neil Shapiro return sys_errlist[errnum];
1315c2aa98e2SPeter Wemm
1316951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
13173299c2f1SGregory Neil Shapiro return buf;
13183299c2f1SGregory Neil Shapiro #endif /* HASSTRERROR */
1319c2aa98e2SPeter Wemm }
1320